org.eclipse.nebula.widgets.grid.Grid Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2012, 2023 EclipseSource 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:
* EclipseSource - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.grid;
import static org.eclipse.swt.internal.widgets.MarkupUtil.checkMarkupPrecondition;
import static org.eclipse.swt.internal.widgets.MarkupUtil.isMarkupEnabledFor;
import static org.eclipse.swt.internal.widgets.MarkupUtil.MarkupTarget.TEXT;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.nebula.widgets.grid.internal.IGridAdapter;
import org.eclipse.nebula.widgets.grid.internal.IScrollBarProxy;
import org.eclipse.nebula.widgets.grid.internal.NullScrollBarProxy;
import org.eclipse.nebula.widgets.grid.internal.ScrollBarProxyAdapter;
import org.eclipse.nebula.widgets.grid.internal.gridkit.GridLCA;
import org.eclipse.nebula.widgets.grid.internal.gridkit.GridThemeAdapter;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.internal.lifecycle.WidgetLCA;
import org.eclipse.rap.rwt.internal.textsize.TextSizeUtil;
import org.eclipse.rap.rwt.internal.theme.Size;
import org.eclipse.rap.rwt.internal.theme.ThemeAdapter;
import org.eclipse.rap.rwt.template.Template;
import org.eclipse.rap.rwt.theme.BoxDimensions;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.TreeListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.internal.SerializableCompatibility;
import org.eclipse.swt.internal.widgets.ICellToolTipAdapter;
import org.eclipse.swt.internal.widgets.ICellToolTipProvider;
import org.eclipse.swt.internal.widgets.ItemProvider;
import org.eclipse.swt.internal.widgets.WidgetTreeVisitor;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.TypedListener;
/**
* Instances of this class implement a selectable user interface object that
* displays a list of images and strings and issue notification when selected.
*
* The item children that may be added to instances of this class must be of
* type {@code GridItem}.
*
*
* - Styles:
* - SWT.SINGLE, SWT.MULTI, SWT.NO_FOCUS, SWT.CHECK, SWT.VIRTUAL
* - Events:
* - Selection, DefaultSelection
*
*/
@SuppressWarnings("restriction")
public class Grid extends Composite {
private static final int MIN_ITEM_HEIGHT = 16;
private static final int GRID_WIDTH = 1;
private List items = new ArrayList();
private List rootItems = new ArrayList();
private List selectedItems = new ArrayList();
private List selectedCells = new ArrayList();
private List columns = new ArrayList();
private List displayOrderedColumns = new ArrayList();
private List columnGroups = new ArrayList();
private GridItem focusItem;
private GridColumn focusColumn;
private GridColumn treeColumn;
private GridColumn rowHeadersColumn;
private boolean isInternalColumn;
private boolean isTree;
private boolean disposing;
private boolean columnHeadersVisible;
private boolean columnFootersVisible;
private boolean linesVisible = true;
private boolean autoHeight;
private int currentVisibleItems;
private int selectionType = SWT.SINGLE;
private boolean selectionEnabled = true;
private boolean cellSelectionEnabled;
private int customItemHeight = -1;
private int groupHeaderHeight;
private Point itemImageSize;
private Listener resizeListener;
private Listener disposeListener;
private boolean isTemporaryResize;
private IScrollBarProxy vScroll;
private IScrollBarProxy hScroll;
private boolean scrollValuesObsolete;
private boolean defaultRowHeadersTextObsolete;
private int topIndex = -1;
private int bottomIndex = -1;
private boolean bottomIndexShownCompletely;
private final IGridAdapter gridAdapter;
boolean hasDifferingHeights;
private boolean hasSpanning;
LayoutCache layoutCache;
/**
* Constructs a new instance of this class given its parent and a style
* value describing its behavior and appearance.
*
*
* @param parent a composite control which will be the parent of the new
* instance (cannot be null)
* @param style the style of control to construct
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the parent is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the parent
*
* @see SWT#SINGLE
* @see SWT#MULTI
*/
public Grid( Composite parent, int style ) {
super( parent, checkStyle( style ) );
if( ( style & SWT.MULTI ) != 0 ) {
selectionType = SWT.MULTI;
}
if( getVerticalBar() != null ) {
getVerticalBar().setVisible( false );
vScroll = new ScrollBarProxyAdapter( getVerticalBar() );
} else {
vScroll = new NullScrollBarProxy();
}
if( getHorizontalBar() != null ) {
getHorizontalBar().setVisible( false );
hScroll = new ScrollBarProxyAdapter( getHorizontalBar() );
} else {
hScroll = new NullScrollBarProxy();
}
gridAdapter = new GridAdapter();
layoutCache = new LayoutCache();
initListeners();
createRowHeadersColumn();
}
/**
* {@inheritDoc}
*/
@Override
public Point computeSize( int wHint, int hHint, boolean changed ) {
checkWidget();
Point rreferredSize = null;
if( wHint == SWT.DEFAULT || hHint == SWT.DEFAULT ) {
rreferredSize = getTableSize();
rreferredSize.x += 2 * getBorderWidth();
rreferredSize.y += 2 * getBorderWidth();
}
int width = 0;
int height = 0;
if( wHint == SWT.DEFAULT ) {
width += rreferredSize.x;
if( getVerticalBar() != null ) {
width += getVerticalBar().getSize().x;
}
} else {
width = wHint;
}
if( hHint == SWT.DEFAULT ) {
height += rreferredSize.y;
if( getHorizontalBar() != null ) {
height += getHorizontalBar().getSize().y;
}
} else {
height = hHint;
}
return new Point( width, height );
}
/**
* Adds the listener to the collection of listeners who will be notified
* when the receiver's selection changes, by sending it one of the messages
* defined in the {@code SelectionListener} interface.
*
* Cell selection events may have Event.detail = SWT.DRAG
when the
* user is drag selecting multiple cells. A follow up selection event will be generated
* when the drag is complete.
*
* @param listener the listener which should be notified
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the listener is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void addSelectionListener( SelectionListener listener ) {
checkWidget();
if( listener == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
TypedListener typedListener = new TypedListener( listener );
addListener( SWT.Selection, typedListener );
addListener( SWT.DefaultSelection, typedListener );
}
/**
* Removes the listener from the collection of listeners who will be
* notified when the receiver's selection changes.
*
* @param listener the listener which should no longer be notified
* @see SelectionListener
* @see #addSelectionListener(SelectionListener)
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void removeSelectionListener( SelectionListener listener ) {
checkWidget();
if( listener == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
removeListener( SWT.Selection, listener );
removeListener( SWT.DefaultSelection, listener );
}
/**
* Adds the listener to the collection of listeners who will be notified
* when the receiver's items changes, by sending it one of the messages
* defined in the {@code TreeListener} interface.
*
* @param listener the listener which should be notified
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the listener is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
* @see TreeListener
* @see #removeTreeListener
* @see org.eclipse.swt.events.TreeEvent
*/
public void addTreeListener( TreeListener listener ) {
checkWidget();
if( listener == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
TypedListener typedListener = new TypedListener( listener );
addListener( SWT.Expand, typedListener );
addListener( SWT.Collapse, typedListener );
}
/**
* Removes the listener from the collection of listeners who will be
* notified when the receiver's items changes.
*
* @param listener the listener which should no longer be notified
* @see TreeListener
* @see #addTreeListener(TreeListener)
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void removeTreeListener( TreeListener listener ) {
checkWidget();
if( listener == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
removeListener( SWT.Expand, listener );
removeListener( SWT.Collapse, listener );
}
/**
* Sets the number of items contained in the receiver.
*
* @param count the number of items
*
* @exception org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
*
*/
public void setItemCount( int count ) {
checkWidget();
int itemCount = Math.max( 0, count );
if( itemCount < items.size() ) {
selectedCells.clear();
}
while( itemCount < items.size() ) {
int flatIndex = items.size() - 1;
items.get( flatIndex ).dispose( flatIndex );
}
while( itemCount > items.size() ) {
new GridItem( this, null, SWT.NONE, -1 );
}
redraw();
}
/**
* Returns the number of items contained in the receiver.
*
* @return the number of items
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public int getItemCount() {
checkWidget();
return items.size();
}
/**
* Returns a (possibly empty) array of {@code GridItem}s which are the
* items in the receiver.
*
* 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.
*
*
* @return the items in the receiver
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridItem[] getItems() {
checkWidget();
return items.toArray( new GridItem[ items.size() ] );
}
/**
* 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
*
* - ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the
* list minus 1 (inclusive)
*
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridItem getItem( int index ) {
checkWidget();
if( index < 0 || index >= items.size() ) {
SWT.error( SWT.ERROR_INVALID_RANGE );
}
return items.get( index );
}
/**
* Returns the item at the given point in the receiver or null if no such
* item exists. The point is in the coordinate system of the receiver.
*
* @param point the point used to locate the item
* @return the item at the given point
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the point is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridItem getItem( Point point ) {
checkWidget();
if( point == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
GridItem result = null;
if( point.x >= 0 && point.x <= getClientArea().width ) {
Point p = new Point( point.x, point.y );
int y = 0;
if( columnHeadersVisible ) {
y += getHeaderHeight();
}
if( p.y > y ) {
int row = getTopIndex();
while( row < items.size() && y <= getClientArea().height && result == null ) {
GridItem currentItem = items.get( row );
if( currentItem.isVisible() ) {
int currentItemHeight = currentItem.getHeight();
if( p.y >= y && p.y < y + currentItemHeight ) {
result = currentItem;
}
y += currentItemHeight;
}
row++;
}
}
}
return result;
}
/**
* 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
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the item is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public int indexOf( GridItem item ) {
checkWidget();
if( item == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
return item.getParent() == this ? items.indexOf( item ) : -1;
}
/**
* Returns the number of root items contained in the receiver.
*
* @return the number of items
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public int getRootItemCount() {
checkWidget();
return rootItems.size();
}
/**
* Returns a (possibly empty) array of {@code GridItem}s which are
* the root items in the receiver.
*
* 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.
*
*
* @return the root items in the receiver
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridItem[] getRootItems() {
checkWidget();
return rootItems.toArray( new GridItem[ rootItems.size() ] );
}
/**
* TODO: JavaDoc
* @param index
* @return the root item
*/
public GridItem getRootItem( int index ) {
checkWidget();
if( index < 0 || index >= rootItems.size() ) {
SWT.error( SWT.ERROR_INVALID_RANGE );
}
return rootItems.get( index );
}
/**
* Returns the next visible item in the table.
*
* @param item item
* @return next visible item or null
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridItem getNextVisibleItem( GridItem item ) {
checkWidget();
GridItem result = null;
int index = items.indexOf( item );
if( index != items.size() - 1 ) {
result = items.get( index + 1 );
while( result != null && !result.isVisible() ) {
index++;
if( index != items.size() - 1 ) {
result = items.get( index + 1 );
} else {
result = null;
}
}
}
return result;
}
/**
* Returns the previous visible item in the table. Passing null for the item
* will return the last visible item in the table.
*
* @param item item or null
* @return previous visible item or if item==null last visible item
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridItem getPreviousVisibleItem( GridItem item ) {
checkWidget();
GridItem result = null;
int index = 0;
if( item == null ) {
index = items.size();
} else {
index = items.indexOf( item );
}
if( index > 0 ) {
result = items.get( index - 1 );
while( result != null && !result.isVisible() ) {
index--;
if( index > 0 ) {
result = items.get( index - 1 );
} else {
result = null;
}
}
}
return result;
}
/**
* Returns the number of columns contained in the receiver. If no
* {@code GridColumn}s were created by the programmer, this value is
* zero, despite the fact that visually, one column of items may be visible.
* This occurs when the programmer uses the table like a list, adding items
* but never creating a column.
*
* @return the number of columns
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public int getColumnCount() {
checkWidget();
return columns.size();
}
/**
* Returns an array of {@code GridColumn}s which are the columns in the
* receiver. If no {@code GridColumn}s were created by the programmer,
* the array is empty, despite the fact that visually, one column of items
* may be visible. This occurs when the programmer uses the table like a
* list, adding items but never creating a column.
*
* 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.
*
*
* @return the items in the receiver
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridColumn[] getColumns() {
checkWidget();
return columns.toArray( new GridColumn[ columns.size() ] );
}
/**
* Returns the column at the given, zero-relative index in the receiver.
* Throws an exception if the index is out of range. If no
* {@code GridColumn}s were created by the programmer, this method will
* throw {@code ERROR_INVALID_RANGE} despite the fact that a single column
* of data may be visible in the table. This occurs when the programmer uses
* the table like a list, adding items but never creating a column.
*
* @param index the index of the column to return
* @return the column at the given index
* @throws IllegalArgumentException
*
* - ERROR_INVALID_RANGE - if the index is not between 0 and the number
* of elements in the list minus 1 (inclusive)
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridColumn getColumn( int index ) {
checkWidget();
if( index < 0 || index > getColumnCount() - 1 ) {
SWT.error( SWT.ERROR_INVALID_RANGE );
}
return columns.get( index );
}
/**
* Returns the column at the given point in the receiver or null if no such
* column exists. The point is in the coordinate system of the receiver.
*
* @param point the point used to locate the column
* @return the column at the given point
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the point is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridColumn getColumn( Point point ) {
checkWidget();
if( point == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
GridColumn overThis = null;
int x2 = 0;
if ( isRowHeaderVisible() ) {
if ( point.x <= rowHeadersColumn.getWidth() ) {
return null;
}
x2 += rowHeadersColumn.getWidth();
}
x2 -= hScroll.getSelection();
for( GridColumn column : displayOrderedColumns ) {
if( !column.isVisible() ) {
continue;
}
if( point.x >= x2 && point.x < x2 + column.getWidth() ) {
overThis = column;
break;
}
x2 += column.getWidth();
}
if( overThis == null ) {
return null;
}
if( hasSpanning ) {
// special logic for column spanning
GridItem item = getItem( point );
if( item != null ) {
int displayColIndex = displayOrderedColumns.indexOf( overThis );
// track back all previous columns and check their spanning
for( int i = 0; i < displayColIndex; i++ ) {
if( !displayOrderedColumns.get( i ).isVisible() ) {
continue;
}
int colIndex = indexOf( displayOrderedColumns.get( i ) );
int span = item.getColumnSpan( colIndex );
if( i + span >= displayColIndex ) {
overThis = displayOrderedColumns.get( i );
break;
}
}
}
}
return overThis;
}
/**
* Searches the receiver's list starting at the first column (index 0) until
* a column is found that is equal to the argument, and returns the index of
* that column. If no column is found, returns -1.
*
* @param column the search column
* @return the index of the column
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the column is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public int indexOf( GridColumn column ) {
checkWidget();
if( column == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
return column.getParent() == this ? columns.indexOf( column ): -1;
}
/**
* Sets the order that the items in the receiver should be displayed in to
* the given argument which is described in terms of the zero-relative
* ordering of when the items were added.
*
* @param order the new order to display the items
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS -if not called from the thread that
* created the receiver
*
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the item order is null
* - ERROR_INVALID_ARGUMENT - if the order is not the same length as the
* number of items, or if an item is listed twice, or if the order splits a
* column group
*
*/
public void setColumnOrder( int[] order ) {
checkWidget();
if( order == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
if( order.length != displayOrderedColumns.size() ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
boolean[] seen = new boolean[ displayOrderedColumns.size() ];
for( int i = 0; i < order.length; i++ ) {
if( order[ i ] < 0 || order[ i ] >= displayOrderedColumns.size() ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
if( seen[ order[ i ] ] ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
seen[ order[ i ] ] = true;
}
if( columnGroups.size() != 0 ) {
GridColumnGroup currentGroup = null;
int columnsInGroup = 0;
for( int i = 0; i < order.length; i++ ) {
GridColumn column = getColumn( order[ i ] );
if( currentGroup != null ) {
if( column.getColumnGroup() != currentGroup && columnsInGroup > 0 ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
} else {
columnsInGroup--;
if( columnsInGroup <= 0 ) {
currentGroup = null;
}
}
} else if( column.getColumnGroup() != null ) {
currentGroup = column.getColumnGroup();
columnsInGroup = currentGroup.getColumns().length - 1;
}
}
}
GridColumn[] columns = getColumns();
int[] oldOrder = getColumnOrder();
displayOrderedColumns.clear();
for( int i = 0; i < order.length; i++ ) {
displayOrderedColumns.add( columns[ order[ i ] ] );
}
for( int i = 0; i < order.length; i++ ) {
if( oldOrder[ i ] != order[ i ] ) {
columns[ order[ i ] ].fireMoved();
}
}
updatePrimaryCheckColumn();
}
/**
* Returns an array of zero-relative integers that map the creation order of
* the receiver's items to the order in which they are currently being
* displayed.
*
* Specifically, the indices of the returned array represent the current
* visual order of the items, and the contents of the array represent the
* creation order of the items.
*
*
* 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.
*
*
* @return the current visual order of the receiver's items
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public int[] getColumnOrder() {
checkWidget();
int[] result = new int[ columns.size() ];
for( int i = 0; i < result.length; i++ ) {
GridColumn column = displayOrderedColumns.get( i );
result[ i ] = columns.indexOf( column );
}
return result;
}
/**
* Returns the next visible column in the table.
*
* @param column column
* @return next visible column or null
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridColumn getNextVisibleColumn( GridColumn column ) {
checkWidget();
GridColumn result = null;
int index = displayOrderedColumns.indexOf( column );
if( index != displayOrderedColumns.size() - 1 ) {
result = displayOrderedColumns.get( index + 1 );
while( result != null && !result.isVisible() ) {
index++;
if( index != displayOrderedColumns.size() - 1 ) {
result = displayOrderedColumns.get( index + 1 );
} else {
result = null;
}
}
}
return result;
}
/**
* Returns the previous visible column in the table.
*
* @param column column
* @return previous visible column or null
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridColumn getPreviousVisibleColumn( GridColumn column ) {
checkWidget();
GridColumn result = null;
int index = 0;
if( column == null ) {
index = displayOrderedColumns.size();
} else {
index = displayOrderedColumns.indexOf( column );
}
if( index > 0 ) {
result = displayOrderedColumns.get( index - 1 );
while( result != null && !result.isVisible() ) {
index--;
if( index > 0 ) {
result = displayOrderedColumns.get( index - 1 );
} else {
result = null;
}
}
}
return result;
}
/**
* Returns the number of column groups contained in the receiver.
*
* @return the number of column groups
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public int getColumnGroupCount() {
checkWidget();
return columnGroups.size();
}
/**
* Returns an array of {@code GridColumnGroup}s which are the column groups in the
* receiver.
*
* 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.
*
*
* @return the column groups in the receiver
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridColumnGroup[] getColumnGroups() {
checkWidget();
return columnGroups.toArray( new GridColumnGroup[ columnGroups.size() ] );
}
/**
* Returns the column group 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 column group to return
* @return the column group at the given index
* @throws IllegalArgumentException
*
* - ERROR_INVALID_RANGE - if the index is not between 0 and the number
* of elements in the list minus 1 (inclusive)
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridColumnGroup getColumnGroup( int index ) {
checkWidget();
if( index < 0 || index >= columnGroups.size() ) {
SWT.error( SWT.ERROR_INVALID_RANGE );
}
return columnGroups.get( index );
}
/**
* Clears the item at the given zero-relative index in the receiver.
* The text, icon and other attributes of the item are set to the default
* value. If the table was created with the SWT.VIRTUAL
style,
* these attributes are requested again as needed.
*
* @param index the index of the item to clear
* @param allChildren true
if all child items of the indexed item should be
* cleared recursively, and false
otherwise
*
* @exception IllegalArgumentException
* - ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)
*
* @exception org.eclipse.swt.SWTException
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
*
*
* @see SWT#VIRTUAL
* @see SWT#SetData
*/
public void clear( int index, boolean allChildren ) {
checkWidget();
if( index < 0 || index >= items.size() ) {
SWT.error( SWT.ERROR_INVALID_RANGE );
}
items.get( index ).clear( allChildren );
redraw();
}
/**
* Clears the items in the receiver which are between the given
* zero-relative start and end indices (inclusive). The text, icon
* and other attributes of the items are set to their default values.
* If the table was created with the SWT.VIRTUAL
style,
* these attributes are requested again as needed.
*
* @param start the start index of the item to clear
* @param end the end index of the item to clear
* @param allChildren true
if all child items of the range of items should be
* cleared recursively, and false
otherwise
*
* @exception IllegalArgumentException
* - ERROR_INVALID_RANGE - if either the start or end are not between 0 and the number of elements in the list minus 1 (inclusive)
*
* @exception org.eclipse.swt.SWTException
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
*
*
* @see SWT#VIRTUAL
* @see SWT#SetData
*/
public void clear( int start, int end, boolean allChildren ) {
checkWidget();
if( start <= end ) {
if( !( 0 <= start && start <= end && end < items.size() ) ) {
SWT.error( SWT.ERROR_INVALID_RANGE );
}
for( int i = start; i <= end; i++ ) {
items.get( i ).clear( allChildren );
}
redraw();
}
}
/**
* Clears the items at the given zero-relative indices in the receiver.
* The text, icon and other attributes of the items are set to their default
* values. If the table was created with the SWT.VIRTUAL
style,
* these attributes are requested again as needed.
*
* @param indices the array of indices of the items
* @param allChildren true
if all child items of the indexed items should be
* cleared recursively, and false
otherwise
*
* @exception IllegalArgumentException
* - ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)
* - ERROR_NULL_ARGUMENT - if the indices array is null
*
* @exception org.eclipse.swt.SWTException
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
*
*
* @see SWT#VIRTUAL
* @see SWT#SetData
*/
public void clear( int[] indices, boolean allChildren ) {
checkWidget();
if( indices == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
if( indices.length > 0 ) {
for( int i = 0; i < indices.length; i++ ) {
if( !isValidItemIndex( indices[ i ] ) ) {
SWT.error( SWT.ERROR_INVALID_RANGE );
}
}
for( int i = 0; i < indices.length; i++ ) {
items.get( indices[ i ] ).clear( allChildren );
}
redraw();
}
}
/**
* Clears all the items in the receiver. The text, icon and other
* attributes of the items are set to their default values. If the
* table was created with the SWT.VIRTUAL
style, these
* attributes are requested again as needed.
*
* @param allChildren true
if all child items of each item should be
* cleared recursively, and false
otherwise
*
* @exception org.eclipse.swt.SWTException
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
*
*
* @see SWT#VIRTUAL
* @see SWT#SetData
*/
public void clearAll( boolean allChildren ) {
checkWidget();
int itemsCount = items.size();
if( itemsCount > 0 ) {
// [if] Note: The parameter allChildren has no effect as all items (not only rootItems)
// are cleared
clear( 0, itemsCount - 1, allChildren );
itemImageSize = null;
setCellToolTipsEnabled( false );
layoutCache.invalidateItemHeight();
}
}
/**
* Enables selection highlighting if the argument is true
.
*
* @param selectionEnabled the selection enabled state
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void setSelectionEnabled( boolean selectionEnabled ) {
checkWidget();
if( !selectionEnabled ) {
selectedItems.clear();
}
this.selectionEnabled = selectionEnabled;
}
/**
* Returns true
if selection is enabled, false otherwise.
*
* @return the selection enabled state
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public boolean getSelectionEnabled() {
checkWidget();
return selectionEnabled;
}
/**
* Returns true if the cells are selectable in the reciever.
*
* @return cell selection enablement status.
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the
* receiver
*
*
* @since 3.13
*/
public boolean getCellSelectionEnabled() {
checkWidget();
return cellSelectionEnabled;
}
/**
* Sets whether cells are selectable in the receiver.
*
* Note: Using markup in the cell text will require data-cell-index attribute to be added
* to the HTML element that points to the cell column index. Row header column (visible or not)
* always has index 0.
*
*
* @param cellSelection the cellSelection to set
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the
* receiver
*
*
* @since 3.13
*/
public void setCellSelectionEnabled( boolean cellSelection ) {
checkWidget();
if( cellSelection ) {
if( ( getStyle() & SWT.SINGLE ) == 0 ) {
// To keep compatibility, one can selected multiple cells
selectionType = SWT.MULTI;
}
selectedItems.clear();
} else {
selectedCells.clear();
}
cellSelectionEnabled = cellSelection;
}
/**
* Returns true if the cells are selectable in the reciever.
*
* @return cell selection enablement status.
*
* @since 3.13
*/
public boolean isCellSelectionEnabled() {
return cellSelectionEnabled;
}
/**
* Selects the item at the given zero-relative index in the receiver. If the
* item at the index was already selected, it remains selected. Indices that
* are out of range are ignored.
*
* If cell selection is enabled, selects all cells at the given index.
*
* @param index the index of the item to select
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void select( int index ) {
checkWidget();
if( selectionEnabled && isValidItemIndex( index ) ) {
if( !cellSelectionEnabled && selectionType == SWT.SINGLE ) {
selectedItems.clear();
}
internalSelect( index );
}
}
/**
* Selects the items in the range specified by the given zero-relative
* indices in the receiver. The range of indices is inclusive. The current
* selection is not cleared before the new items are selected.
*
* If an item in the given range is not selected, it is selected. If an item
* in the given range was already selected, it remains selected. Indices
* that are out of range are ignored and no items will be selected if start
* is greater than end. If the receiver is single-select and there is more
* than one item in the given range, then all indices are ignored.
*
* If cell selection is enabled, all cells within the given range are selected.
*
* @param start the start of the range
* @param end the end of the range
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
* @see Grid#setSelection(int,int)
*/
public void select( int start, int end ) {
checkWidget();
if( selectionEnabled && !( selectionType == SWT.SINGLE && start != end ) ) {
if( !cellSelectionEnabled && selectionType == SWT.SINGLE ) {
selectedItems.clear();
}
for( int index = Math.max( 0, start ); index <= Math.min( items.size() - 1, end ); index++ ) {
internalSelect( index );
}
}
}
/**
* Selects the items at the given zero-relative indices in the receiver. The
* current selection is not cleared before the new items are selected.
*
* If the item at a given index is not selected, it is selected. If the item
* at a given index was already selected, it remains selected. Indices that
* are out of range and duplicate indices are ignored. If the receiver is
* single-select and multiple indices are specified, then all indices are
* ignored.
*
* If cell selection is enabled, all cells within the given indices are
* selected.
*
* @param indices the array of indices for the items to select
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the array of indices is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
* @see Grid#setSelection(int[])
*/
public void select( int[] indices ) {
checkWidget();
if( indices == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
if( selectionEnabled && !( selectionType == SWT.SINGLE && indices.length > 1 ) ) {
if( !cellSelectionEnabled && selectionType == SWT.SINGLE ) {
selectedItems.clear();
}
for( int i = 0; i < indices.length; i++ ) {
internalSelect( indices[ i ] );
}
}
}
/**
* Selects all of the items in the receiver.
*
* If the receiver is single-select, do nothing. If cell selection is enabled,
* all cells are selected.
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void selectAll() {
checkWidget();
if( selectionEnabled && selectionType != SWT.SINGLE ) {
if( cellSelectionEnabled ) {
selectAllCells();
} else {
selectedItems.clear();
selectedItems.addAll( items );
}
}
}
/**
* Selects the given cell. Invalid cells are ignored.
*
* @param cell
* point whose x value is a column index and y value is an item
* index
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the item is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public void selectCell( Point cell ) {
checkWidget();
if( cellSelectionEnabled ) {
if( cell == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
addToCellSelection( cell );
}
}
/**
* Selects the given cells. Invalid cells are ignored.
*
* @param cells
* an arry of points whose x value is a column index and y value is
* an item index
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the set of cells or an individual
* cell is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public void selectCells( Point[] cells ) {
checkWidget();
if( cellSelectionEnabled ) {
if( cells == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
for( Point cell : cells ) {
if( cell == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
}
for( Point cell : cells ) {
addToCellSelection( cell );
}
}
}
/**
* Selects all cells in the receiver.
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public void selectAllCells() {
checkWidget();
internalSelectAll();
}
/**
* Selects all cells in the given column in the receiver.
*
* @param col
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public void selectColumn( int col ) {
checkWidget();
selectCells( getCells( getColumn( col ) ) );
}
/**
* Selects all cells in the given column group in the receiver.
*
* @param colGroup
* the column group
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public void selectColumnGroup( int colGroup ) {
selectColumnGroup( getColumnGroup( colGroup ) );
}
/**
* Selects all cells in the given column group in the receiver.
*
* @param colGroup
* the column group
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public void selectColumnGroup( GridColumnGroup colGroup ) {
checkWidget();
selectCells( getCells( colGroup ) );
}
/**
* Deselects the item at the given zero-relative index in the receiver. If
* the item at the index was already deselected, it remains deselected.
* Indices that are out of range are ignored.
*
* If cell selection is enabled, all cells in the specified item are deselected.
*
* @param index the index of the item to deselect
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void deselect( int index ) {
checkWidget();
if( isValidItemIndex( index ) ) {
internalDeselect( index );
}
}
/**
* Deselects the items at the given zero-relative indices in the receiver.
* If the item at the given zero-relative index in the receiver is selected,
* it is deselected. If the item at the index was not selected, it remains
* deselected. The range of the indices is inclusive. Indices that are out
* of range are ignored.
*
* If cell selection is enabled, all cells in the given range are deselected.
*
* @param start the start index of the items to deselect
* @param end the end index of the items to deselect
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void deselect( int start, int end ) {
checkWidget();
for( int index = Math.max( 0, start ); index <= Math.min( items.size() - 1, end ); index++ ) {
internalDeselect( index );
}
}
/**
* Deselects the items at the given zero-relative indices in the receiver.
* If the item at the given zero-relative index in the receiver is selected,
* it is deselected. If the item at the index was not selected, it remains
* deselected. Indices that are out of range and duplicate indices are
* ignored.
*
* If cell selection is enabled, all cells in the given items are deselected.
*
* @param indices the array of indices for the items to deselect
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the set of indices is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void deselect( int[] indices ) {
checkWidget();
if( indices == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
for( int i = 0; i < indices.length; i++ ) {
internalDeselect( indices[ i ] );
}
}
/**
* Deselects all selected items in the receiver. If cell selection is enabled,
* all cells are deselected.
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void deselectAll() {
checkWidget();
internalDeselectAll();
}
/**
* Deselects the given cell in the receiver. If the given cell is already
* deselected it remains deselected. Invalid cells are ignored.
*
* @param cell
* cell to deselect.
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the cell is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public void deselectCell( Point cell ) {
checkWidget();
if( cell == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
selectedCells.remove( cell );
}
/**
* Deselects the given cells. Invalid cells are ignored.
*
* @param cells
* the cells to deselect.
*
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the set of cells or any cell is
* null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public void deselectCells( Point[] cells ) {
checkWidget();
if( cells == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
for( Point cell : cells ) {
if( cell == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
}
for( Point cell : cells ) {
selectedCells.remove( cell );
}
}
/**
* Deselects all selected cells in the receiver.
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public void deselectAllCells() {
checkWidget();
selectedCells.clear();
}
/**
* Selects the item at the given zero-relative index in the receiver. The
* current selection is first cleared, then the new item is selected.
*
* If cell selection is enabled, all cells within the item at the given index
* are selected.
*
* @param index the index of the item to select
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void setSelection( int index ) {
checkWidget();
if( selectionEnabled && isValidItemIndex( index ) ) {
internalDeselectAll();
internalSelect( index );
}
}
/**
* Selects the items in the range specified by the given zero-relative
* indices in the receiver. The range of indices is inclusive. The current
* selection is cleared before the new items are selected.
*
* Indices that are out of range are ignored and no items will be selected
* if start is greater than end. If the receiver is single-select and there
* is more than one item in the given range, then all indices are ignored.
*
* If cell selection is enabled, all cells within the given range are selected.
*
* @param start the start index of the items to select
* @param end the end index of the items to select
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
* @see Grid#deselectAll()
* @see Grid#select(int,int)
*/
public void setSelection( int start, int end ) {
checkWidget();
if( selectionEnabled && !( selectionType == SWT.SINGLE && start != end ) ) {
internalDeselectAll();
for( int index = Math.max( 0, start ); index <= Math.min( items.size() - 1, end ); index++ ) {
internalSelect( index );
}
}
}
/**
* Selects the items at the given zero-relative indices in the receiver. The
* current selection is cleared before the new items are selected.
*
* Indices that are out of range and duplicate indices are ignored. If the
* receiver is single-select and multiple indices are specified, then all
* indices are ignored.
*
* If cell selection is enabled, all cells within the given indices are selected.
*
* @param indices the indices of the items to select
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the array of indices is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
* @see Grid#deselectAll()
* @see Grid#select(int[])
*/
public void setSelection( int[] indices ) {
checkWidget();
if( indices == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
if( selectionEnabled && !( selectionType == SWT.SINGLE && indices.length > 1 ) ) {
internalDeselectAll();
for( int i = 0; i < indices.length; i++ ) {
internalSelect( indices[ i ] );
}
}
}
/**
* Sets the receiver's selection to be the given array of items. The current
* selection is cleared before the new items are selected.
*
* Items that are not in the receiver are ignored. If the receiver is
* single-select and multiple items are specified, then all items are
* ignored. If cell selection is enabled, all cells within the given items
* are selected.
*
* @param items the array of items
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the array of items is null
* - ERROR_INVALID_ARGUMENT - if one of the items has been disposed
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
* @see Grid#deselectAll()
* @see Grid#select(int[])
* @see Grid#setSelection(int[])
*/
public void setSelection( GridItem[] items ) {
checkWidget();
if( items == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
if( selectionEnabled && !( selectionType == SWT.SINGLE && items.length > 1 ) ) {
internalDeselectAll();
for( GridItem item : items ) {
if( item != null ) {
if( item.isDisposed() ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
internalSelect( this.items.indexOf( item ) );
}
}
}
}
/**
* Returns a array of {@code GridItem}s that are currently selected in the
* receiver. The order of the items is unspecified. An empty array indicates
* that no items are selected.
*
* Note: This is not the actual structure used by the receiver to maintain
* its selection, so modifying the array will not affect the receiver.
*
* If cell selection is enabled, any items which contain at least one selected
* cell are returned.
*
* @return an array representing the selection
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridItem[] getSelection() {
checkWidget();
if( cellSelectionEnabled ) {
List items = new ArrayList<>();
int itemCount = getItemCount();
for( Point cell : selectedCells ) {
if( cell.y >= 0 && cell.y < itemCount ) {
GridItem item = getItem( cell.y );
if( !items.contains( item ) ) {
items.add( item );
}
}
}
return items.toArray( new GridItem[] {} );
}
return selectedItems.toArray( new GridItem[ selectedItems.size() ] );
}
/**
* Returns the number of selected items contained in the receiver. If cell selection
* is enabled, the number of items with at least one selected cell are returned.
*
* @return the number of selected items
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public int getSelectionCount() {
checkWidget();
if( cellSelectionEnabled ) {
List items = new ArrayList<>();
for( Point cell : selectedCells ) {
GridItem item = getItem( cell.y );
if( !items.contains( item ) ) {
items.add( item );
}
}
return items.size();
}
return selectedItems.size();
}
/**
* Returns the number of selected cells contained in the receiver.
*
* @return the number of selected cells
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public int getCellSelectionCount() {
checkWidget();
return selectedCells.size();
}
/**
* Selects the selection to the given cell. The existing selection is cleared
* before selecting the given cell.
*
* @param cell
* point whose x value is a column index and y value is an item
* index
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the item is null
* - ERROR_INVALID_ARGUMENT - if the cell is invalid
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public void setCellSelection( Point cell ) {
checkWidget();
if( cellSelectionEnabled ) {
if( cell == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
if( !isValidCell( cell ) ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
selectedCells.clear();
addToCellSelection( cell );
}
}
/**
* Selects the selection to the given set of cell. The existing selection is
* cleared before selecting the given cells.
*
* @param cells
* point array whose x values is a column index and y value is an
* item index
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the cell array or an individual cell
* is null
* - ERROR_INVALID_ARGUMENT - if the a cell is invalid
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public void setCellSelection( Point[] cells ) {
checkWidget();
if( cellSelectionEnabled ) {
if( cells == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
for( Point cell : cells ) {
if( cell == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
if( !isValidCell( cell ) ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
}
selectedCells.clear();
for( Point cell : cells ) {
addToCellSelection( cell );
}
}
}
/**
* Returns an array of cells that are currently selected in the receiver. The order of the items
* is unspecified. An empty array indicates that no items are selected.
*
* Note: This is not the actual structure used by the receiver to maintain its selection, so
* modifying the array will not affect the receiver.
*
*
* @return an array representing the cell selection
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the
* receiver
*
*
* @since 3.13
*/
public Point[] getCellSelection() {
checkWidget();
return selectedCells.toArray( new Point[ selectedCells.size() ] );
}
/**
* Returns the zero-relative index of the item which is currently selected
* in the receiver, or -1 if no item is selected. If cell selection is enabled,
* returns the index of first item that contains at least one selected cell.
*
* @return the index of the selected item
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public int getSelectionIndex() {
checkWidget();
int result = -1;
if( cellSelectionEnabled ) {
if( selectedCells.size() != 0 ) {
result = selectedCells.get( 0 ).y;
}
} else {
if( selectedItems.size() != 0 ) {
result = items.indexOf( selectedItems.get( 0 ) );
}
}
return result;
}
/**
* Returns the zero-relative indices of the items which are currently
* selected in the receiver. The order of the indices is unspecified. The
* array is empty if no items are selected.
*
* Note: This is not the actual structure used by the receiver to maintain
* its selection, so modifying the array will not affect the receiver.
*
* If cell selection is enabled, returns the indices of any items which
* contain at least one selected cell.
*
* @return the array of indices of the selected items
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public int[] getSelectionIndices() {
checkWidget();
int[] result = new int[ 0 ];
if( cellSelectionEnabled ) {
List selectedRows = new ArrayList();
for( Point cell : selectedCells ) {
GridItem item = getItem( cell.y );
if( !selectedRows.contains( item ) ) {
selectedRows.add( item );
}
}
result = new int[ selectedRows.size() ];
for( int i = 0; i < result.length; i++ ) {
GridItem item = selectedRows.get( i );
result[ i ] = items.indexOf( item );
}
} else {
result = new int[ selectedItems.size() ];
for( int i = 0; i < result.length; i++ ) {
GridItem item = selectedItems.get( i );
result[ i ] = items.indexOf( item );
}
}
return result;
}
/**
* Returns {@code true} if the item is selected, and {@code false}
* otherwise. Indices out of range are ignored. If cell selection is
* enabled, returns true if the item at the given index contains at
* least one selected cell.
*
* @param index the index of the item
* @return the visibility state of the item at the index
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public boolean isSelected( int index ) {
checkWidget();
boolean result = false;
if( isValidItemIndex( index ) ) {
if( cellSelectionEnabled ) {
for( Point cell : selectedCells ) {
if( cell.y == index ) {
result = true;
}
}
} else {
result = isSelected( items.get( index ) );
}
}
return result;
}
/**
* Returns true if the given item is selected. If cell selection is enabled,
* returns true if the given item contains at least one selected cell.
*
* @param item item
* @return true if the item is selected.
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the item is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public boolean isSelected( GridItem item ) {
checkWidget();
if( item == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
boolean result = false;
if( cellSelectionEnabled ) {
int index = items.indexOf( item );
if( index != -1 ) {
for( Point cell : selectedCells ) {
if( cell.y == index ) {
result = true;
}
}
}
} else {
result = selectedItems.contains( item );
}
return result;
}
/**
* Returns true if the given cell is selected.
*
* @param cell
* cell
* @return true if the cell is selected.
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the cell is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public boolean isCellSelected( Point cell ) {
checkWidget();
if( cell == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
return selectedCells.contains( cell );
}
/**
* Returns the cell at the given point in the receiver or null if no such cell
* exists. The point is in the coordinate system of the receiver.
*
* @param point
* the point used to locate the cell
* @return the cell at the given point
* @throws IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the point is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public Point getCell( Point point ) {
checkWidget();
if( point == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
if( point.x < 0 || point.x > getClientArea().width ) {
return null;
}
GridItem item = getItem( point );
GridColumn column = getColumn( point );
if( item != null && column != null ) {
return new Point( indexOf( column ), indexOf( item ) );
}
return null;
}
/**
* Removes the item from the receiver at the given zero-relative index.
*
* @param index the index for the item
* @throws IllegalArgumentException
*
* - ERROR_INVALID_RANGE - if the index is not between 0 and the number
* of elements in the list minus 1 (inclusive)
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void remove( int index ) {
checkWidget();
if( index < 0 || index > items.size() - 1 ) {
SWT.error( SWT.ERROR_INVALID_RANGE );
}
items.get( index ).dispose( index );
}
/**
* Removes the items from the receiver which are between the given
* zero-relative start and end indices (inclusive).
*
* @param start the start of the range
* @param end the end of the range
* @throws IllegalArgumentException
*
* - ERROR_INVALID_RANGE - if either the start or end are not between 0
* and the number of elements in the list minus 1 (inclusive)
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void remove( int start, int end ) {
checkWidget();
for( int i = end; i >= start; i-- ) {
if( i < 0 || i > items.size() - 1 ) {
SWT.error( SWT.ERROR_INVALID_RANGE );
}
items.get( i ).dispose( i );
}
}
/**
* Removes the items from the receiver's list at the given zero-relative
* indices.
*
* @param indices the array of indices of the items
* @throws IllegalArgumentException
*
* - ERROR_INVALID_RANGE - if the index is not between 0 and the number
* of elements in the list minus 1 (inclusive)
* - ERROR_NULL_ARGUMENT - if the indices array is null
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void remove( int[] indices ) {
checkWidget();
if( indices == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
GridItem[] removeThese = new GridItem[ indices.length ];
for( int i = 0; i < indices.length; i++ ) {
int index = indices[ i ];
if( isValidItemIndex( index ) ) {
removeThese[ i ] = items.get( index );
} else {
SWT.error( SWT.ERROR_INVALID_RANGE );
}
}
for( int i = 0; i < removeThese.length; i++ ) {
removeThese[ i ].dispose();
}
}
/**
* Removes all of the items from the receiver.
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void removeAll() {
checkWidget();
while( items.size() > 0 ) {
int flatIndex = items.size() - 1;
items.get( flatIndex ).dispose( flatIndex );
}
}
/**
* Marks the receiver's header as visible if the argument is {@code true},
* and marks it invisible otherwise.
*
* @param show the new visibility state
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void setHeaderVisible( boolean show ) {
checkWidget();
if( columnHeadersVisible != show ) {
columnHeadersVisible = show;
layoutCache.invalidateHeaderHeight();
scheduleRedraw();
}
}
/**
* Returns {@code true} if the receiver's header is visible, and
* {@code false} otherwise.
*
* @return the receiver's header's visibility state
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public boolean getHeaderVisible() {
checkWidget();
return columnHeadersVisible;
}
/**
* Returns the height of the column headers. If this table has column
* groups, the returned value includes the height of group headers.
*
* @return height of the column header row
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public int getHeaderHeight() {
checkWidget();
if( !layoutCache.hasHeaderHeight() ) {
layoutCache.headerHeight = computeHeaderHeight();
}
return layoutCache.headerHeight;
}
/**
* Marks the receiver's footer as visible if the argument is {@code true},
* and marks it invisible otherwise.
*
* @param show the new visibility state
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void setFooterVisible( boolean show ) {
checkWidget();
if( columnFootersVisible != show ) {
columnFootersVisible = show;
layoutCache.invalidateFooterHeight();
scheduleRedraw();
}
}
/**
* Returns {@code true} if the receiver's footer is visible, and {@code false} otherwise
* @return the receiver's footer's visibility state
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public boolean getFooterVisible() {
checkWidget();
return columnFootersVisible;
}
/**
* Returns the height of the column footers.
*
* @return height of the column footer row
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public int getFooterHeight() {
checkWidget();
if( !layoutCache.hasFooterHeight() ) {
layoutCache.footerHeight = computeFooterHeight();
}
return layoutCache.footerHeight;
}
/**
* Returns the height of the column group headers.
*
* @return height of column group headers
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public int getGroupHeaderHeight() {
checkWidget();
if( !layoutCache.hasHeaderHeight() ) {
layoutCache.headerHeight = computeHeaderHeight();
}
return groupHeaderHeight;
}
/**
* Sets the line visibility.
*
* @param linesVisible The linesVisible to set.
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void setLinesVisible( boolean linesVisible ) {
checkWidget();
this.linesVisible = linesVisible;
}
/**
* Returns true if the lines are visible.
*
* @return Returns the linesVisible.
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public boolean getLinesVisible() {
checkWidget();
return linesVisible;
}
/**
* Sets the focused item to the given item.
*
* @param item item to focus.
* @throws IllegalArgumentException
*
* - ERROR_INVALID_ARGUMENT - if item is disposed
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void setFocusItem( GridItem item ) {
checkWidget();
if( item == null || item.isDisposed() || item.getParent() != this || !item.isVisible() ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
focusItem = item;
}
/**
* Returns the current item in focus.
*
* @return item in focus or {@code null}.
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public GridItem getFocusItem() {
checkWidget();
return focusItem;
}
/**
* Sets the focused column to the given column. Column focus is only applicable
* when cell selection is enabled.
*
* @param column
* column to focus.
* @throws IllegalArgumentException
*
* - ERROR_INVALID_ARGUMENT - if item is disposed
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public void setFocusColumn( GridColumn column ) {
checkWidget();
if( column == null
|| column.isDisposed()
|| column.getParent() != this
|| !column.isVisible() )
{
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
if( isCellSelectionEnabled() ) {
focusColumn = column;
}
}
/**
* Returns the current column in focus.
* Column focus is only applicable when cell selection is enabled.
*
* @return column in focus or {@code null}.
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*
* @since 3.13
*/
public GridColumn getFocusColumn() {
checkWidget();
return isCellSelectionEnabled() ? focusColumn : null;
}
/**
* Returns the current cell in focus. If cell selection is disabled, this method
* returns null.
*
* @return cell in focus or {@code null}. x represents the column and y the row
* the cell is in
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.13
*/
public Point getFocusCell() {
checkWidget();
if( !cellSelectionEnabled ) {
return null;
}
int x = -1;
int y = -1;
if( focusColumn != null ) {
x = indexOf( focusColumn );
}
if( focusItem != null ) {
y = indexOf( focusItem );
}
return new Point( x, y );
}
/**
* Sets the default height for this Grid
's items. When
* this method is called, all existing items are resized
* to the specified height and items created afterwards will be
* initially sized to this height.
*
* As long as no default height was set by the client through this method,
* the preferred height of the first item in this Grid
is
* used as a default for all items (and is returned by {@link #getItemHeight()}).
*
* @param height default height in pixels
* @throws IllegalArgumentException
*
* - ERROR_INVALID_ARGUMENT - if the height is < 1
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*
* @see GridItem#getHeight()
*/
public void setItemHeight( int height ) {
checkWidget();
if( height < 1 ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
if( customItemHeight != height ) {
customItemHeight = height;
hasDifferingHeights = false;
scheduleRedraw();
}
}
/**
* Returns the default height of the items
* in this Grid
. See {@link #setItemHeight(int)}
* for details.
*
* @return default height of items
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
* @see #setItemHeight(int)
*/
public int getItemHeight() {
checkWidget();
if( customItemHeight == -1 ) {
if( !layoutCache.hasItemHeight() ) {
layoutCache.itemHeight = computeItemHeight();
}
return layoutCache.itemHeight;
}
return customItemHeight;
}
@Override
public void setFont( Font font ) {
super.setFont( font );
layoutCache.invalidateItemHeight();
scheduleRedraw();
}
/**
* Sets the zero-relative index of the item which is currently at the top of
* the receiver. This index can change when items are scrolled or new items
* are added and removed.
*
* @param index the index of the top item
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void setTopIndex( int index ) {
checkWidget();
if( isValidItemIndex( index ) ) {
updateScrollBars();
GridItem item = items.get( index );
if( item.isVisible() && vScroll.getVisible() ) {
int vScrollAmount = 0;
for( int i = 0; i < index; i++ ) {
if( items.get( i ).isVisible() ) {
vScrollAmount++;
}
}
vScroll.setSelection( vScrollAmount );
invalidateTopBottomIndex();
redraw();
}
}
}
/**
* Returns the zero-relative index of the item which is currently at the top
* of the receiver. This index can change when items are scrolled or new
* items are added or removed.
*
* @return the index of the top item
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public int getTopIndex() {
checkWidget();
if( topIndex == -1 ) {
updateScrollBars();
if( vScroll.getVisible() ) {
int firstVisibleIndex = vScroll.getSelection();
if( isTree ) {
Iterator iterator = items.iterator();
int row = firstVisibleIndex + 1;
while( row > 0 && iterator.hasNext() ) {
GridItem item = iterator.next();
if( item.isVisible() ) {
row--;
if( row == 0 ) {
firstVisibleIndex = items.indexOf( item );
}
}
}
}
topIndex = firstVisibleIndex;
} else {
topIndex = 0;
}
}
return topIndex;
}
/**
* Shows the item. If the item is already showing in the receiver, this
* method simply returns. Otherwise, the items are scrolled until the item
* is visible.
*
* @param item the item to be shown
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
* - ERROR_INVALID_ARGUMENT - if 'item' is not contained in the receiver
*
*/
public void showItem( GridItem item ) {
checkWidget();
if( item == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
if( item.isDisposed() ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
if( item.getParent() == this ) {
int visibleGridHeight = getVisibleGridHeight();
if( visibleGridHeight >= 1 ) {
updateScrollBars();
GridItem parent = item.getParentItem();
while( parent != null ) {
if( !parent.isExpanded() ) {
parent.setExpanded( true );
parent.fireEvent( SWT.Expand );
}
parent = parent.getParentItem();
}
if( !isShown( item ) ) {
setTopIndex( items.indexOf( item ) );
}
}
}
}
/**
* Shows the column. If the column is already showing in the receiver, this
* method simply returns. Otherwise, the columns are scrolled until the
* column is visible.
*
* @param column the column to be shown
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void showColumn( GridColumn column ) {
checkWidget();
if( column == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
if( column.isDisposed() ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
if( column.getParent() == this ) {
updateScrollBars();
if( !column.isVisible() ) {
GridColumnGroup group = column.getColumnGroup();
group.setExpanded( !group.getExpanded() );
if( group.getExpanded() ) {
group.notifyListeners( SWT.Expand, new Event() );
} else {
group.notifyListeners( SWT.Collapse, new Event() );
}
}
if( hScroll.getVisible() ) {
int offset = hScroll.getSelection();
int x = getColumnHeaderXPosition( column );
if( x < 0 || x + column.getWidth() > getClientArea().width ) {
if( x >= 0 && column.getWidth() <= getClientArea().width ) {
x -= getClientArea().width - column.getWidth();
}
hScroll.setSelection( offset + x );
}
}
}
}
/**
* Shows the selection. If the selection is already showing in the receiver,
* this method simply returns. Otherwise, the items are scrolled until the
* selection is visible.
*
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
*
*/
public void showSelection() {
checkWidget();
GridItem item = null;
if( cellSelectionEnabled ) {
if( selectedCells.size() != 0 ) {
Point cell = selectedCells.get( 0 );
item = getItem( cell.y );
showItem( item );
GridColumn column = getColumn( cell.x );
showColumn( column );
}
} else {
if( selectedItems.size() != 0 ) {
item = selectedItems.get( 0 );
showItem( item );
}
}
}
/**
* Sets the value of the auto-height feature. When enabled, this feature resizes the height of
* rows to reflect the content of cells with word-wrapping enabled. Cell word-wrapping is enabled
* via the GridColumn.setWordWrap(boolean) method. If column headers have word-wrapping enabled,
* this feature will also resize the height of the column headers as necessary.
*
* @param autoHeight Set to true to enable this feature, false (default) otherwise.
*/
public void setAutoHeight( boolean autoHeight ) {
checkWidget();
if( this.autoHeight != autoHeight ) {
this.autoHeight = autoHeight;
layoutCache.invalidateHeaderHeight();
layoutCache.invalidateFooterHeight();
scheduleRedraw();
}
}
/**
* Returns the value of the auto-height feature, which resizes row heights and column header
* heights based on word-wrapped content.
*
* @return Returns whether or not the auto-height feature is enabled.
* @see #setAutoHeight(boolean)
*/
public boolean isAutoHeight() {
checkWidget();
return autoHeight;
}
/**
* Recalculate the height of the header
*
* @since 3.4
*/
public void recalculateHeader() {
int previous = getHeaderHeight();
layoutCache.headerHeight = computeHeaderHeight();
if( previous != layoutCache.headerHeight ) {
scrollValuesObsolete = true;
scheduleRedraw();
}
}
/**
* Marks the receiver's row header as visible if the argument is {@code true},
* and marks it invisible otherwise.
*
* @param show
* the new visibility state
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.14
*/
public void setRowHeaderVisible( boolean show ) {
setRowHeaderVisible( show, 10 );
}
/**
* Marks the receiver's row header as visible if the argument is {@code true},
* and marks it invisible otherwise.
*
* @param show
* the new visibility state
* @param minWidth
* the minimun width of the row column
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.14
*/
public void setRowHeaderVisible( boolean show, int minWidth ) {
checkWidget();
if( rowHeadersColumn != null ) {
if( show ) {
rowHeadersColumn.setMinimumWidth( Math.max( 10, minWidth ) );
} else {
rowHeadersColumn.setMinimumWidth( 0 );
rowHeadersColumn.setWidth( 0 );
}
}
}
/**
* Sets the row header width to the specified value. This automatically disables
* the auto width feature of the grid.
*
* @param width
* the width of the row header
* @see #getItemHeaderWidth()
*
* @since 3.14
*/
public void setItemHeaderWidth( int width ) {
checkWidget();
if( rowHeadersColumn != null ) {
rowHeadersColumn.setWidth( width );
}
}
/**
* Returns the row header width or 0 if row headers are not visible.
*
* @return the width of the row headers
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.14
*/
public int getItemHeaderWidth() {
checkWidget();
return rowHeadersColumn != null ? rowHeadersColumn.getWidth() : 0;
}
/**
* Returns {@code true} if the receiver's row header is visible, and
* {@code false} otherwise.
*
*
* @return the receiver's row header's visibility state
* @throws org.eclipse.swt.SWTException
*
* - ERROR_WIDGET_DISPOSED - if the receiver has been
* disposed
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread
* that created the receiver
*
*
* @since 3.14
*/
public boolean isRowHeaderVisible() {
checkWidget();
return rowHeadersColumn != null && rowHeadersColumn.getWidth() > 0;
}
/**
* Sets the value of the word-wrap feature for row headers. When enabled, this
* feature will word-wrap the contents of row headers.
*
* @param enabled
* Set to true to enable this feature, false (default) otherwise.
* @see #isWordWrapHeader()
*
* @since 3.14
*/
public void setWordWrapHeader( boolean enabled ) {
checkWidget();
if( rowHeadersColumn != null ) {
rowHeadersColumn.setWordWrap( enabled );
}
}
/**
* Returns the value of the row header word-wrap feature, which word-wraps the
* content of row headers.
*
* @return Returns whether or not the row header word-wrap feature is enabled.
* @see #setWordWrapHeader(boolean)
*
* @since 3.14
*/
public boolean isWordWrapHeader() {
checkWidget();
return rowHeadersColumn != null ? rowHeadersColumn.getWordWrap() : false;
}
@Override
@SuppressWarnings("unchecked")
public T getAdapter( Class adapter ) {
if( adapter == ItemProvider.class
|| adapter == IGridAdapter.class
|| adapter == ICellToolTipAdapter.class )
{
return ( T )gridAdapter;
}
if( adapter == WidgetLCA.class ) {
return ( T )GridLCA.INSTANCE;
}
return super.getAdapter( adapter );
}
@Override
public void setData( String key, Object value ) {
if( !RWT.MARKUP_ENABLED.equals( key ) || !isMarkupEnabledFor( this ) ) {
checkMarkupPrecondition( key, TEXT, () -> items.size() == 0 );
if( RWT.ROW_TEMPLATE.equals( key ) && value instanceof Template ) {
rowHeadersColumn = null;
}
super.setData( key, value );
}
}
int newItem( GridItem item, int index, boolean root ) {
int row = 0;
GridItem parentItem = item.getParentItem();
if( !isTree && parentItem != null ) {
isTree = true;
}
int flatIndex = index;
// Have to convert indexes, this method needs a flat index, the method is called with indexes
// that are relative to the level
if( root && index != -1 ) {
if( index >= rootItems.size() ) {
flatIndex = -1;
} else {
flatIndex = items.indexOf( rootItems.get( index ) );
}
} else if( !root ) {
if( index >= parentItem.getItemCount() || index == -1 ) {
GridItem rightMostDescendent = parentItem;
while( rightMostDescendent.hasChildren() ) {
int lastChildIndex = rightMostDescendent.getItemCount() - 1;
rightMostDescendent = rightMostDescendent.getItem( lastChildIndex );
}
flatIndex = items.indexOf( rightMostDescendent ) + 1;
} else {
flatIndex = items.indexOf( parentItem.getItem( index ) );
}
}
if( flatIndex == -1 ) {
items.add( item );
row = items.size() - 1;
} else {
items.add( flatIndex, item );
row = flatIndex;
}
updateVisibleItems( 1 );
scheduleRedraw();
return row;
}
void removeItem( int index ) {
GridItem item = items.remove( index );
if( !disposing ) {
selectedItems.remove (item );
Point[] cells = getCells( item );
for( int i = 0; i < cells.length; i++ ) {
selectedCells.remove( cells[ i ] );
}
if( focusItem == item ) {
focusItem = null;
}
if( item.isVisible() ) {
updateVisibleItems( -1 );
}
scheduleRedraw();
}
}
void newRootItem( GridItem item, int index ) {
if( index == -1 || index >= rootItems.size() ) {
rootItems.add( item );
item.index = rootItems.size() - 1;
} else {
rootItems.add( index, item );
item.index = index;
}
adjustItemIndices( item.index + 1 );
}
void removeRootItem( int index ) {
rootItems.remove( index );
adjustItemIndices( index );
}
private void adjustItemIndices( int start ) {
for( int i = start; i < rootItems.size(); i++ ) {
rootItems.get( i ).index = i;
}
}
void newColumn( GridColumn column, int index ) {
if( !isInternalColumn ) {
if( index == -1 ) {
columns.add( column );
displayOrderedColumns.add( column );
} else {
columns.add( index, column );
displayOrderedColumns.add( index, column );
}
updatePrimaryCheckColumn();
for( GridItem item : items ) {
item.columnAdded( index );
}
if( column.isCheck() ) {
layoutCache.invalidateItemHeight();
}
layoutCache.invalidateHeaderHeight();
layoutCache.invalidateFooterHeight();
scheduleRedraw();
}
}
void removeColumn( GridColumn column ) {
int index = columns.indexOf( column );
if( cellSelectionEnabled ) {
List removeSelectedCells = new ArrayList<>();
for( Point cell : selectedCells ) {
if( cell.x == index ) {
removeSelectedCells.add( cell );
}
}
if( removeSelectedCells.size() > 0 ) {
selectedCells.removeAll( removeSelectedCells );
}
for( Point cell : selectedCells ) {
if( cell.x >= index ) {
cell.x-- ;
}
}
}
columns.remove( index );
displayOrderedColumns.remove( column );
if( focusColumn == column ) {
focusColumn = null;
}
updatePrimaryCheckColumn();
for( GridItem item : items ) {
item.columnRemoved( index );
}
if( column.isCheck() ) {
layoutCache.invalidateItemHeight();
}
layoutCache.invalidateHeaderHeight();
layoutCache.invalidateFooterHeight();
scheduleRedraw();
}
void newColumnGroup( GridColumnGroup group ) {
columnGroups.add( group );
if( columnGroups.size() == 1 ) {
layoutCache.invalidateHeaderHeight();
}
scheduleRedraw();
}
void removeColumnGroup( GridColumnGroup group ) {
columnGroups.remove( group );
if( columnGroups.size() == 0 ) {
layoutCache.invalidateHeaderHeight();
}
scheduleRedraw();
}
boolean isDisposing() {
return disposing;
}
void updateVisibleItems( int amount ) {
currentVisibleItems += amount;
}
GridColumn[] getColumnsInOrder() {
checkWidget();
return displayOrderedColumns.toArray( new GridColumn[ columns.size() ] );
}
void imageSetOnItem( Image image ) {
if( image != null && itemImageSize == null ) {
Rectangle imageBounds = image.getBounds();
itemImageSize = new Point( imageBounds.width, imageBounds.height );
layoutCache.invalidateItemHeight();
scheduleRedraw();
}
}
int getMaxContentWidth( GridColumn column ) {
doRedraw();
return getMaxInnerWidth( getRootItems(), columns.indexOf( column ) );
}
int getBottomIndex() {
checkWidget();
if( bottomIndex == -1 ) {
int topIndex = getTopIndex();
int visibleGridHeight = getVisibleGridHeight();
if( items.size() == 0 ) {
bottomIndex = 0;
} else if( visibleGridHeight < 1 ) {
bottomIndex = topIndex;
} else {
RowRange range = getRowRange( topIndex, visibleGridHeight, false, false );
bottomIndex = range.endIndex;
bottomIndexShownCompletely = range.height <= visibleGridHeight;
}
}
return bottomIndex;
}
Point getOrigin( GridColumn column, GridItem item ) {
int x = column.getLeft() - hScroll.getSelection();
int y = 0;
if( item != null ) {
if( columnHeadersVisible ) {
y += getHeaderHeight();
}
int topIndex = getTopIndex();
int itemIndex = items.indexOf( item );
if( itemIndex == -1 ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
while( topIndex != itemIndex ) {
if( topIndex < itemIndex ) {
GridItem currentItem = items.get( topIndex );
if( currentItem.isVisible() ) {
y += currentItem.getHeight();
}
topIndex++;
} else if( topIndex > itemIndex ) {
topIndex--;
GridItem currentItem = items.get( topIndex );
if( currentItem.isVisible() ) {
y -= currentItem.getHeight();
}
}
}
}
return new Point( x, y );
}
boolean isShown( GridItem item ) {
checkWidget();
boolean result = false;
if( item.isVisible() ) {
int itemIndex = items.indexOf( item );
if( itemIndex == -1 ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
int firstVisibleIndex = getTopIndex();
int lastVisibleIndex = getBottomIndex();
result = ( itemIndex >= firstVisibleIndex && itemIndex < lastVisibleIndex )
|| ( itemIndex == lastVisibleIndex && bottomIndexShownCompletely );
}
return result;
}
private void doRedraw() {
if( isVirtual() && items.size() > 0 ) {
for( int index = getTopIndex(); index <= getBottomIndex(); index++ ) {
GridItem item = items.get( index );
if( item.isVisible() ) {
item.ensureItemData();
item.handleVirtual();
}
}
}
updateDefaultRowHeadersText();
updateScrollBars();
}
boolean isVirtual() {
return ( getStyle() & SWT.VIRTUAL ) != 0;
}
private void updateDefaultRowHeadersText() {
if( isRowHeaderVisible() && defaultRowHeadersTextObsolete ) {
int rowCounter = 1;
for( int index = 0; index < items.size(); index++ ) {
GridItem item = items.get( index );
if( item.isVisible() ) {
item.setDefaultHeaderText( Integer.toString( rowCounter++ ) );
}
}
defaultRowHeadersTextObsolete = false;
}
}
void updateScrollBars() {
if( scrollValuesObsolete ) {
Point preferredSize = getTableSize();
Rectangle clientArea = getScrollableArea();
for( int doublePass = 1; doublePass <= 2; doublePass++ ) {
if( preferredSize.y > clientArea.height ) {
vScroll.setVisible( true );
} else {
vScroll.setVisible( false );
vScroll.setValues( 0, 0, 1, 1, 1, 1 );
}
if( preferredSize.x > clientArea.width ) {
hScroll.setVisible( true );
} else {
hScroll.setVisible( false );
hScroll.setValues( 0, 0, 1, 1, 1, 1 );
}
clientArea = getScrollableArea();
}
if( vScroll.getVisible() ) {
int max = currentVisibleItems;
int thumb = 1;
int visibleGridHeight = getVisibleGridHeight();
if( !hasDifferingHeights ) {
thumb = visibleGridHeight / getItemHeight();
} else if( visibleGridHeight >= 1 ) {
RowRange range = getRowRange( -1, visibleGridHeight, true, true );
max -= range.rows - 1;
}
int selection = Math.min( vScroll.getSelection(), max );
vScroll.setValues( selection, 0, max, thumb, 1, thumb );
}
if( hScroll.getVisible() ) {
int hiddenArea = preferredSize.x - clientArea.width;
int selection = Math.min( hScroll.getSelection(), hiddenArea );
hScroll.setValues( selection, 0, preferredSize.x, clientArea.width, 5, clientArea.width );
}
scrollValuesObsolete = false;
}
}
private Rectangle getScrollableArea() {
Rectangle clientArea = getClientArea();
clientArea.width -= getItemHeaderWidth();
return clientArea;
}
protected IScrollBarProxy getHorizontalScrollBarProxy() {
checkWidget();
return hScroll;
}
protected IScrollBarProxy getVerticalScrollBarProxy() {
checkWidget();
return vScroll;
}
private void initListeners() {
resizeListener = new Listener() {
@Override
public void handleEvent( Event event ) {
onResize();
}
};
addListener( SWT.Resize, resizeListener );
disposeListener = new Listener() {
@Override
public void handleEvent( Event event ) {
onDispose( event );
}
};
addListener( SWT.Dispose, disposeListener );
}
private void onResize() {
if( TextSizeUtil.isTemporaryResize() ) {
isTemporaryResize = true;
layoutCache.invalidateHeaderHeight();
layoutCache.invalidateFooterHeight();
layoutCache.invalidateItemHeight();
} else {
if( isTemporaryResize) {
isTemporaryResize = false;
repackColumns();
}
scheduleRedraw();
}
}
private void onDispose( Event event ) {
// We only want to dispose of our items and such *after* anybody else who may have been
// listening to the dispose has had a chance to do whatever.
removeListener( SWT.Resize, resizeListener );
removeListener( SWT.Dispose, disposeListener );
notifyListeners( SWT.Dispose, event );
event.type = SWT.None;
disposing = true;
for( GridItem item : items ) {
item.dispose();
}
for( GridColumn column : columns ) {
column.dispose();
}
for( GridColumnGroup group : columnGroups ) {
group.dispose();
}
if( rowHeadersColumn != null ) {
rowHeadersColumn.dispose();
}
}
void setCellToolTipsEnabled( boolean enabled ) {
setData( ICellToolTipProvider.ENABLE_CELL_TOOLTIP, Boolean.valueOf( enabled ) );
}
private Point getTableSize() {
int width = 0;
int height = 0;
if( columnHeadersVisible ) {
height += getHeaderHeight();
}
if( columnFootersVisible ) {
height += getFooterHeight();
}
height += getGridHeight();
for( GridColumn column : columns ) {
if( column.isVisible() ) {
width += column.getWidth();
}
}
return new Point( width, height );
}
private int getGridHeight() {
int result = 0;
if( hasDifferingHeights ) {
for( GridItem item : items ) {
if( item.isVisible() ) {
result += item.getHeight();
}
}
} else {
result = currentVisibleItems * getItemHeight();
}
return result;
}
private int getVisibleGridHeight() {
int headerHeight = columnHeadersVisible ? getHeaderHeight() : 0;
int footerHeight = columnFootersVisible ? getFooterHeight() : 0;
return getClientArea().height - headerHeight - footerHeight;
}
private static int getMaxInnerWidth( GridItem[] items, int index ) {
int maxInnerWidth = 0;
for( GridItem item : items ) {
if( item.isResolved() ) {
maxInnerWidth = Math.max( maxInnerWidth, item.getPreferredWidth( index ) );
if( item.isExpanded() ) {
int innerWidth = getMaxInnerWidth( item.getItems(), index );
maxInnerWidth = Math.max( maxInnerWidth, innerWidth );
}
}
}
return maxInnerWidth;
}
private void internalSelect( int index ) {
if( isValidItemIndex( index ) ) {
GridItem item = items.get( index );
if( cellSelectionEnabled ) {
selectCells( getCells( item ) );
} else if( !selectedItems.contains( item ) ) {
selectedItems.add( item );
}
}
}
private void internalSelectAll() {
for( int i = 0; i < items.size(); i++ ) {
GridItem item = items.get( i );
if( item.isVisible() ) {
internalSelect( i );
}
}
}
private void internalDeselect( int index ) {
if( isValidItemIndex( index ) ) {
GridItem item = items.get( index );
if( cellSelectionEnabled ) {
deselectCells( getCells( item ) );
} else if( selectedItems.contains( item ) ) {
selectedItems.remove( item );
}
}
}
private void internalDeselectAll() {
if( cellSelectionEnabled ) {
selectedCells.clear();
} else {
selectedItems.clear();
}
}
private Point[] getCells( GridItem item ) {
List cells = new ArrayList<>();
int itemIndex = items.indexOf( item );
int span = 0;
for( GridColumn nextCol : displayOrderedColumns ) {
if( span > 0 ) {
span-- ;
continue;
}
if( !nextCol.isVisible() ) {
continue;
}
span = item.getColumnSpan( indexOf( nextCol ) );
cells.add( new Point( indexOf( nextCol ), itemIndex ) );
}
return cells.toArray( new Point[ 0 ] );
}
private Point[] getCells( GridColumn col ) {
List cells = new ArrayList<>();
int colIndex = indexOf( col );
int columnAtPosition = 0;
for( GridColumn nextCol : displayOrderedColumns ) {
if( !nextCol.isVisible() ) {
continue;
}
if( nextCol == col ) {
break;
}
columnAtPosition++ ;
}
GridItem item = null;
if( getItemCount() > 0 ) {
item = getItem( 0 );
}
while( item != null ) {
// is cell spanned
int position = -1;
boolean spanned = false;
for( GridColumn nextCol : displayOrderedColumns ) {
if( !nextCol.isVisible() ) {
continue;
}
if( nextCol == col ) {
break;
}
int span = item.getColumnSpan( indexOf( nextCol ) );
if( position + span >= columnAtPosition ) {
spanned = true;
break;
}
}
if( !spanned && item.getColumnSpan( colIndex ) == 0 ) {
cells.add( new Point( colIndex, indexOf( item ) ) );
}
item = getNextVisibleItem( item );
}
return cells.toArray( new Point[ 0 ] );
}
private Point[] getCells( GridColumnGroup colGroup ) {
List cells = new ArrayList<>();
for( GridColumn col : colGroup.getColumns() ) {
for( Point cell : getCells( col ) ) {
cells.add( cell );
}
}
return cells.toArray( new Point[ 0 ] );
}
private void addToCellSelection( Point newCell ) {
if( newCell.x < 0 || newCell.x >= columns.size() ) {
return;
}
if( newCell.y < 0 || newCell.y >= items.size() ) {
return;
}
Iterator it = selectedCells.iterator();
boolean found = false;
while( it.hasNext() ) {
Point p = it.next();
if( newCell.equals( p ) ) {
found = true;
break;
}
}
if( !found ) {
if( selectionType == SWT.SINGLE && selectedCells.size() > 0 ) {
return;
}
selectedCells.add( newCell );
}
}
private void updatePrimaryCheckColumn() {
if( ( getStyle() & SWT.CHECK ) == SWT.CHECK ) {
for( GridColumn column : columns ) {
column.setTableCheck( false );
}
if( treeColumn != null ) {
treeColumn.setTableCheck( true );
} else if( displayOrderedColumns.size() > 0 ) {
displayOrderedColumns.get( 0 ).setTableCheck( true );
}
}
}
private int computeItemHeight() {
int result = Math.max( getItemImageSize().y, TextSizeUtil.getCharHeight( getFont() ) );
if( hasCheckBoxes() ) {
result = Math.max( getCheckBoxImageOuterSize().height, result );
}
BoxDimensions cellPadding = getCellPadding();
result += cellPadding.top + cellPadding.bottom;
result += GRID_WIDTH;
result = Math.max( result, MIN_ITEM_HEIGHT );
return result;
}
private int computeHeaderHeight() {
int result = 0;
groupHeaderHeight = 0;
if( columnHeadersVisible ) {
int columnHeaderHeight = 0;
for( int i = 0; i < getColumnCount(); i++ ) {
GridColumn column = columns.get( i );
Font font = column.getHeaderFont();
String text = column.getText();
Image image = column.getImage();
int wrapWidth = autoHeight && column.getHeaderWordWrap() ? column.getHeaderWrapWidth() : 0;
int computedHeight = computeColumnHeight( font, text, image, 0, wrapWidth );
columnHeaderHeight = Math.max( columnHeaderHeight, computedHeight );
}
for( int i = 0; i < getColumnGroupCount(); i++ ) {
GridColumnGroup group = columnGroups.get( i );
Font font = group.getHeaderFont();
String text = group.getText();
Image image = group.getImage();
int chevronHeight = group.getChevronHeight();
int wrapWidth = autoHeight && group.getHeaderWordWrap() ? group.getHeaderWrapWidth() : 0;
int computedHeight = computeColumnHeight( font, text, image, chevronHeight, wrapWidth );
groupHeaderHeight = Math.max( groupHeaderHeight, computedHeight );
}
result = columnHeaderHeight + groupHeaderHeight;
}
return result;
}
private int computeFooterHeight() {
int result = 0;
if( columnFootersVisible ) {
int columnFooterHeight = 0;
for( int i = 0; i < getColumnCount(); i++ ) {
GridColumn column = columns.get( i );
Font font = column.getFooterFont();
String text = column.getFooterText();
Image image = column.getFooterImage();
int wrapWidth = autoHeight && column.getHeaderWordWrap() ? column.getFooterWrapWidth() : 0;
int computedHeight = computeColumnHeight( font, text, image, 0, wrapWidth );
columnFooterHeight= Math.max( columnFooterHeight, computedHeight );
}
result = columnFooterHeight;
}
return result;
}
private int computeColumnHeight( Font font,
String text,
Image image,
int minHeight,
int wrapWidth )
{
int result = minHeight;
int textHeight = 0;
if( text.contains( "\n" ) || wrapWidth > 0 ) {
textHeight = TextSizeUtil.textExtent( font, text, wrapWidth ).y;
} else {
textHeight = TextSizeUtil.getCharHeight( font );
}
result = Math.max( result, textHeight );
int imageHeight = image == null ? 0 : image.getBounds().height;
result = Math.max( result, imageHeight );
BoxDimensions headerPadding = getHeaderPadding();
result += headerPadding.top + headerPadding.bottom;
result += getThemeAdapter().getHeaderBorderBottomWidth( this );
return result;
}
private void repackColumns() {
for( int i = 0; i < getColumnCount(); i++ ) {
columns.get( i ).repack();
}
}
private int getColumnHeaderXPosition( GridColumn column ) {
int result = -1;
if( column.isVisible() ) {
result = column.getLeft() - hScroll.getSelection();
}
return result;
}
private int getCellLeft( int index ) {
return getColumn( index ).getLeft();
}
private int getCellWidth( int index ) {
GridColumn column = getColumn( index );
return column.isVisible() ? column.getWidth() : 0;
}
private int getCheckBoxOffset( int index ) {
int result = -1;
BoxDimensions padding = getCellPadding();
if( isColumnCentered( index )
&& !isTreeColumn( index )
&& !hasColumnImages( index )
&& !hasColumnTexts( index ) )
{
result = ( getCellWidth( index ) - getCheckBoxImageSize().width ) / 2;
result = Math.max( result, padding.left );
}
if( result == -1 ) {
result = getCheckBoxMargin().left;
if( !isTreeColumn( index ) ) {
result += padding.left;
}
}
return result;
}
private int getCheckBoxWidth( int index ) {
return getColumn( index ).isCheck() ? getCheckBoxImageSize().width : 0;
}
private int getImageOffset( int index ) {
int result = 0;
if( !isTreeColumn( index ) ) {
result += getCellPadding().left;
}
if( getColumn( index ).isCheck() ) {
result += getCheckBoxImageOuterSize().width;
}
return result;
}
private int getImageWidth( int index ) {
if( hasColumnImages( index ) ) {
int availableWidth = getCellWidth( index );
if( !isTreeColumn( index ) ) {
availableWidth -= getCellPadding().left;
}
availableWidth = Math.max( 0, availableWidth );
return Math.min( getItemImageSize().x, availableWidth );
}
return 0;
}
private int getTextOffset( int index ) {
int result = getImageOffset( index );
if( hasColumnImages( index ) ) {
result += getItemImageSize().x;
result += getCellSpacing();
}
return result;
}
private int getTextWidth( int index ) {
return Math.max( 0, getCellWidth( index ) - getTextOffset( index ) - getCellPadding().right );
}
private int getRowHeaderImageOffset() {
return getCellPadding().left;
}
private int getRowHeaderImageWidth() {
if( hasColumnImages( Integer.MIN_VALUE ) ) {
int availableWidth = Math.max( 0, getItemHeaderWidth() - getCellPadding().left );
return Math.min( getItemImageSize().x, availableWidth );
}
return 0;
}
private int getRowHeaderTextOffset() {
int result = getRowHeaderImageOffset();
if( hasColumnImages( Integer.MIN_VALUE ) ) {
result += getItemImageSize().x;
result += getCellSpacing();
}
return result;
}
private int getRowHeaderTextWidth() {
return Math.max( 0, getItemHeaderWidth() - getRowHeaderTextOffset() - getCellPadding().right );
}
Point getItemImageSize() {
Point result = new Point( 0, 0 );
if( itemImageSize != null ) {
result.x = itemImageSize.x;
result.y = itemImageSize.y;
}
return result;
}
boolean hasColumnImages( int index ) {
if( index == Integer.MIN_VALUE ) {
return rowHeadersColumn != null && rowHeadersColumn.imageCount > 0;
}
return getColumn( index ).imageCount > 0;
}
boolean hasColumnTexts( int index ) {
if( index == Integer.MIN_VALUE ) {
return rowHeadersColumn != null && rowHeadersColumn.textCount > 0;
}
return getColumn( index ).textCount > 0;
}
private boolean hasCheckBoxes() {
boolean result = ( getStyle() & SWT.CHECK ) != 0;
for( int i = 0; i < getColumnCount() && !result; i++ ) {
GridColumn column = columns.get( i );
if( column.isCheck() ) {
result = true;
}
}
return result;
}
Size getCheckBoxImageOuterSize() {
Size imageSize = getCheckBoxImageSize();
BoxDimensions margin = getCheckBoxMargin();
int width = imageSize.width + margin.left + margin.right;
int height = imageSize.height + margin.top + margin.bottom;
return new Size( width, height );
}
void setTreeColumn( GridColumn column ) {
treeColumn = column;
updatePrimaryCheckColumn();
}
boolean isTreeColumn( int index ) {
boolean result = false;
if( isTree && index < columns.size() ) {
if( treeColumn != null ) {
result = columns.get( index ) == treeColumn;
} else {
result = index == getColumnOrder()[ 0 ];
}
}
return result;
}
private boolean isColumnCentered( int index ) {
return getColumn( index ).getAlignment() == SWT.CENTER;
}
private Size getCheckBoxImageSize() {
if( !layoutCache.hasCheckBoxImageSize() ) {
layoutCache.checkBoxImageSize = getThemeAdapter().getCheckBoxImageSize( this );
}
return layoutCache.checkBoxImageSize;
}
private BoxDimensions getCheckBoxMargin() {
if( !layoutCache.hasCheckBoxMargin() ) {
layoutCache.checkBoxMargin = getThemeAdapter().getCheckBoxMargin( this );
}
return layoutCache.checkBoxMargin;
}
BoxDimensions getCellPadding() {
if( !layoutCache.hasCellPadding() ) {
layoutCache.cellPadding = getThemeAdapter().getCellPadding( this );
}
return layoutCache.cellPadding;
}
BoxDimensions getHeaderPadding() {
if( !layoutCache.hasHeaderPadding() ) {
layoutCache.headerPadding = getThemeAdapter().getHeaderPadding( this );
}
return layoutCache.headerPadding;
}
int getIndentationWidth() {
if( !isTree ) {
return 0;
}
if( !layoutCache.hasIndentationWidth() ) {
layoutCache.indentationWidth = getThemeAdapter().getIndentationWidth( this );
}
return layoutCache.indentationWidth;
}
int getCellSpacing() {
if( !layoutCache.hasCellSpacing() ) {
layoutCache.cellSpacing = getThemeAdapter().getCellSpacing( this );
}
return layoutCache.cellSpacing;
}
private GridThemeAdapter getThemeAdapter() {
return ( GridThemeAdapter )getAdapter( ThemeAdapter.class );
}
private static int checkStyle( int style ) {
int mask = SWT.BORDER
| SWT.LEFT_TO_RIGHT
// | SWT.RIGHT_TO_LEFT
| SWT.H_SCROLL
| SWT.V_SCROLL
| SWT.SINGLE
| SWT.MULTI
| SWT.NO_FOCUS
| SWT.CHECK
| SWT.VIRTUAL;
int result = style & mask;
result |= SWT.DOUBLE_BUFFERED;
// TODO: [if] Remove it when cell selection is implemented
result |= SWT.FULL_SELECTION;
return result;
}
private RowRange getRowRange( int start,
int availableHeight,
boolean forceEndCompletelyInside,
boolean inverse )
{
RowRange result = new RowRange();
int startIndex = start;
if( startIndex == -1 ) {
if( inverse ) {
startIndex = items.size();
}
do {
startIndex += inverse ? -1 : 1;
} while( isValidItemIndex( startIndex ) && !items.get( startIndex ).isVisible() );
if( !isValidItemIndex( startIndex ) ) {
result = null;
}
}
if( result != null ) {
if( startIndex < 0 || startIndex >= items.size() || !items.get( startIndex ).isVisible() ) {
SWT.error( SWT.ERROR_INVALID_ARGUMENT );
}
if( availableHeight <= 0 ) {
result.startIndex = startIndex;
result.endIndex = startIndex;
result.rows = 0;
result.height = 0;
} else if( isTree || hasDifferingHeights ) {
int otherIndex = startIndex;
int consumedItems = 0;
int consumedHeight = 0;
consumedItems++;
consumedHeight += items.get( otherIndex ).getHeight();
boolean abort = false;
while( consumedHeight + 1 <= availableHeight && !abort ) {
int nextIndex = otherIndex;
GridItem nextItem;
do {
nextIndex += inverse ? -1 : 1;
if( isValidItemIndex( nextIndex ) ) {
nextItem = items.get( nextIndex );
} else {
nextItem = null;
}
} while( nextItem != null && !nextItem.isVisible() );
if( nextItem == null
|| forceEndCompletelyInside
&& !( consumedHeight + nextItem.getHeight() <= availableHeight ) )
{
abort = true;
} else {
consumedItems++;
consumedHeight += nextItem.getHeight();
otherIndex = nextIndex;
}
}
result.startIndex = !inverse ? startIndex : otherIndex;
result.endIndex = !inverse ? otherIndex : startIndex;
result.rows = consumedItems;
result.height = consumedHeight;
} else {
int availableRows = availableHeight / getItemHeight();
if( !forceEndCompletelyInside && availableRows * getItemHeight() < availableHeight ) {
availableRows++;
}
int otherIndex = startIndex + ( ( availableRows - 1 ) * ( inverse ? -1 : 1 ) );
otherIndex = Math.max( otherIndex, 0 );
otherIndex = Math.min( otherIndex, items.size() - 1 );
result.startIndex = !inverse ? startIndex : otherIndex;
result.endIndex = !inverse ? otherIndex : startIndex;
result.rows = result.endIndex - result.startIndex + 1;
result.height = getItemHeight() * result.rows;
}
}
return result;
}
private boolean isValidItemIndex( int index ) {
return index >= 0 && index < items.size();
}
private boolean isValidCell( Point cell ) {
if( cell.x < 0 || cell.x >= columns.size() ) {
return false;
}
if( cell.y < 0 || cell.y >= items.size() ) {
return false;
}
return true;
}
int internalIndexOf( GridItem item ) {
return items.indexOf( item );
}
void scheduleRedraw() {
invalidateScrollBars();
invalidateTopBottomIndex();
redraw();
}
void invalidateTopBottomIndex() {
topIndex = -1;
bottomIndex = -1;
}
void invalidateScrollBars() {
scrollValuesObsolete = true;
}
void invalidateDefaultRowHeadersText() {
defaultRowHeadersTextObsolete = true;
redraw();
}
void setHasSpanning( boolean hasSpanning ) {
this.hasSpanning = hasSpanning;
}
boolean isRowHeadersColumn( GridColumn column ) {
return column != null && column == rowHeadersColumn;
}
GridColumn getRowHeadersColumn() {
return rowHeadersColumn;
}
private void createRowHeadersColumn() {
isInternalColumn = true;
rowHeadersColumn = new GridColumn( this, SWT.NONE );
rowHeadersColumn.setMoveable( false );
rowHeadersColumn.setMinimumWidth( 0 );
rowHeadersColumn.setWidth( 0 );
isInternalColumn = false;
}
private boolean isFixedColumn( GridColumn column ) {
int fixedColumns = getFixedColumns();
if( fixedColumns <= 0 ) {
return false;
} else if( isRowHeadersColumn( column ) ) {
return true;
}
int[] columnOrder = getColumnOrder();
int visualIndex = -1;
for( int i = 0; i < columnOrder.length && visualIndex == -1; i++ ) {
if( indexOf( column ) == columnOrder[ i ] ) {
visualIndex = i;
}
}
return visualIndex < fixedColumns - 1;
}
private int getFixedColumns() {
if( !( getData( RWT.ROW_TEMPLATE ) instanceof Template ) ) {
Object fixedColumns = getData( RWT.FIXED_COLUMNS );
if( fixedColumns instanceof Integer ) {
return ( ( Integer )fixedColumns ).intValue() + 1;
}
return 1;
}
return -1;
}
////////////////
// Inner classes
private static class RowRange {
public int startIndex;
public int endIndex;
public int rows;
public int height;
}
private final class GridAdapter
implements IGridAdapter, ICellToolTipAdapter, ItemProvider, SerializableCompatibility
{
private String toolTipText;
private ICellToolTipProvider provider;
public GridAdapter() {
provider = new CellToolTipProvider();
}
@Override
public void invalidateTopIndex() {
invalidateTopBottomIndex();
redraw();
}
@Override
public int getIndentationWidth() {
return Grid.this.getIndentationWidth();
}
@Override
public int getCellLeft( int index ) {
return Grid.this.getCellLeft( index );
}
@Override
public int getCellWidth( int index ) {
return Grid.this.getCellWidth( index );
}
@Override
public int getCheckBoxOffset( int index ) {
return Grid.this.getCheckBoxOffset( index );
}
@Override
public int getCheckBoxWidth( int index ) {
return Grid.this.getCheckBoxWidth( index );
}
@Override
public int getImageOffset( int index ) {
return Grid.this.getImageOffset( index );
}
@Override
public int getImageWidth( int index ) {
return Grid.this.getImageWidth( index );
}
@Override
public int getTextOffset( int index ) {
return Grid.this.getTextOffset( index );
}
@Override
public int getTextWidth( int index ) {
return Grid.this.getTextWidth( index );
}
@Override
public int getRowHeaderImageOffset() {
return Grid.this.getRowHeaderImageOffset();
}
@Override
public int getRowHeaderImageWidth() {
return Grid.this.getRowHeaderImageWidth();
}
@Override
public int getRowHeaderTextOffset() {
return Grid.this.getRowHeaderTextOffset();
}
@Override
public int getRowHeaderTextWidth() {
return Grid.this.getRowHeaderTextWidth();
}
@Override
public int getItemIndex( GridItem item ) {
return item.index;
}
@Override
public ICellToolTipProvider getCellToolTipProvider() {
return provider;
}
@Override
public void setCellToolTipProvider( ICellToolTipProvider provider ) {
this.provider = provider;
}
@Override
public String getCellToolTipText() {
return toolTipText;
}
@Override
public void setCellToolTipText( String toolTipText ) {
this.toolTipText = toolTipText;
}
@Override
public void doRedraw() {
Grid.this.doRedraw();
}
@Override
public void provideItems( WidgetTreeVisitor visitor ) {
for( GridColumnGroup columnGroup : columnGroups ) {
visitor.visit( columnGroup );
}
if( rowHeadersColumn != null ) {
visitor.visit( rowHeadersColumn );
}
for( GridColumn column : columns ) {
visitor.visit( column );
}
if( isVirtual() ) {
for( GridItem item : items ) {
if( item.isResolved() ) {
visitor.visit( item );
}
}
} else {
for( GridItem item : items ) {
visitor.visit( item );
}
}
}
@Override
public int getFixedColumns() {
return Grid.this.getFixedColumns();
}
@Override
public boolean isFixedColumn( GridColumn column ) {
return Grid.this.isFixedColumn( column );
}
@Override
public int getTreeColumn() {
int offset = rowHeadersColumn != null ? 1 : 0;
if( treeColumn != null ) {
return indexOf( treeColumn ) + offset;
} else if( getColumnCount() > 0 ) {
return getColumnOrder()[ 0 ] + offset;
}
return -1;
}
@Override
public int getSelectionType() {
return selectionType;
}
@Override
public GridColumn getRowHeadersColumn() {
return Grid.this.getRowHeadersColumn();
}
}
private final class CellToolTipProvider
implements ICellToolTipProvider, SerializableCompatibility
{
@Override
public void getToolTipText( Item item, int columnIndex ) {
String toolTipText = ( ( GridItem )item ).getToolTipText( columnIndex );
getAdapter( ICellToolTipAdapter.class ).setCellToolTipText( toolTipText );
}
}
static final class LayoutCache implements SerializableCompatibility {
private static final int UNKNOWN = -1;
int headerHeight = UNKNOWN;
int footerHeight = UNKNOWN;
int itemHeight = UNKNOWN;
int cellSpacing = UNKNOWN;
int indentationWidth = UNKNOWN;
BoxDimensions cellPadding;
BoxDimensions headerPadding;
BoxDimensions checkBoxMargin;
Size checkBoxImageSize;
public boolean hasHeaderPadding() {
return headerPadding != null;
}
public void invalidateHeaderPadding() {
headerPadding = null;
}
public boolean hasHeaderHeight() {
return headerHeight != UNKNOWN;
}
public void invalidateHeaderHeight() {
headerHeight = UNKNOWN;
}
public boolean hasFooterHeight() {
return footerHeight != UNKNOWN;
}
public void invalidateFooterHeight() {
footerHeight = UNKNOWN;
}
public boolean hasItemHeight() {
return itemHeight != UNKNOWN;
}
public void invalidateItemHeight() {
itemHeight = UNKNOWN;
}
public boolean hasCellSpacing() {
return cellSpacing != UNKNOWN;
}
public void invalidateCellSpacing() {
cellSpacing = UNKNOWN;
}
public boolean hasIndentationWidth() {
return indentationWidth != UNKNOWN;
}
public void invalidateIndentationWidth() {
indentationWidth = UNKNOWN;
}
public boolean hasCellPadding() {
return cellPadding != null;
}
public void invalidateCellPadding() {
cellPadding = null;
}
public boolean hasCheckBoxMargin() {
return checkBoxMargin != null;
}
public void invalidateCheckBoxMargin() {
checkBoxMargin = null;
}
public boolean hasCheckBoxImageSize() {
return checkBoxImageSize != null;
}
public void invalidateCheckBoxImageSize() {
checkBoxImageSize = null;
}
public void invalidateAll() {
invalidateHeaderPadding();
invalidateHeaderHeight();
invalidateFooterHeight();
invalidateItemHeight();
invalidateCellSpacing();
invalidateCellPadding();
invalidateCheckBoxMargin();
invalidateCheckBoxImageSize();
invalidateIndentationWidth();
}
}
}