blob: a48b392d7fc642f6a02755deca06ad5aaa76c98e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2002-2006 Innoopract Informationssysteme GmbH.
* 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:
* Innoopract Informationssysteme GmbH - initial API and implementation
******************************************************************************/
package org.eclipse.swt.widgets;
import java.util.*;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.internal.graphics.FontSizeEstimation;
import org.eclipse.swt.internal.widgets.IItemHolderAdapter;
import org.eclipse.swt.internal.widgets.ItemHolder;
/**
* <p>Current state of Table implementation:</p>
* <ul>
* <li>Though Table inherits the font property from Control, it is currently
* not evaluated client-side.</li>
* <li>Though it is possible to create a table with MULTI style, only SINGLE
* selections are implemented. This also applies when using setSelection with
* more than one TableItem</li>
* <li>linesVisible defaults to <code>false</code> as in SWT and can be queried
* with getLinesVisible. The setLinesVisible methd is not yet implemented.</li>
* <li>VIRTUAL not yet implemented</li>
* <li>showSelection and showItem currently do a very rough proximation since
* getClientArea is not yet implemented properly</li>
* <li>Tables created with style BORDER are not yet drawn correctly</li>
* <li>Scroll bars stay enabled even though the table itself is disabled. This
* is due to a qooxdoo limitation, see http://bugzilla.qooxdoo.org/post_bug.cgi
* </li>
* <li>No images yet</li>
* </ul>
*/
public class Table extends Composite {
// handle the fact that we have two item types to deal with
private final class CompositeItemHolder implements IItemHolderAdapter {
public void add( final Item item ) {
if( item instanceof TableItem ) {
itemHolder.add( item );
} else {
columnHolder.add( item );
}
}
public void insert( final Item item, final int index ) {
if( item instanceof TableItem ) {
itemHolder.insert( item, index );
} else {
columnHolder.insert( item, index );
}
}
public void remove( final Item item ) {
if( item instanceof TableItem ) {
itemHolder.remove( item );
} else {
columnHolder.remove( item );
}
}
public Item[] getItems() {
Item[] items = itemHolder.getItems();
Item[] columns = columnHolder.getItems();
Item[] result = new Item[ items.length + columns.length ];
System.arraycopy( columns, 0, result, 0, columns.length );
System.arraycopy( items, 0, result, columns.length, items.length );
return result;
}
}
private static final int GRID_WIDTH = 1;
private static final int DEFAULT_ITEM_HEIGHT = 15;
private static final TableItem[] EMPTY_SELECTION = new TableItem[ 0 ];
private final ItemHolder itemHolder;
private final ItemHolder columnHolder;
private TableItem[] selection;
private boolean linesVisible;
private boolean headerVisible;
private int topIndex;
public Table( final Composite parent, final int style ) {
super( parent, checkStyle( style ) );
itemHolder = new ItemHolder( TableItem.class );
columnHolder = new ItemHolder( TableColumn.class );
selection = EMPTY_SELECTION;
}
public Object getAdapter( final Class adapter ) {
Object result;
if( adapter == IItemHolderAdapter.class ) {
result = new CompositeItemHolder();
} else {
result = super.getAdapter( adapter );
}
return result;
}
///////////////////////////
// Column handling methods
public int getColumnCount() {
checkWidget();
return columnHolder.size();
}
public TableColumn[] getColumns() {
checkWidget();
return (org.eclipse.swt.widgets.TableColumn[] )columnHolder.getItems();
}
public TableColumn getColumn( final int index ) {
checkWidget();
return ( TableColumn )columnHolder.getItem( index );
}
public int indexOf( final TableColumn tableColumn ) {
checkWidget();
if( tableColumn == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
return columnHolder.indexOf( tableColumn );
}
////////////////////////
// Item handling methods
public int getItemCount() {
checkWidget();
return itemHolder.size();
}
public TableItem[] getItems() {
checkWidget();
return (org.eclipse.swt.widgets.TableItem[] )itemHolder.getItems();
}
public TableItem getItem( final int index ) {
checkWidget();
return ( TableItem )itemHolder.getItem( index );
}
public int indexOf( final TableItem tableItem ) {
checkWidget();
if( tableItem == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
return itemHolder.indexOf( tableItem );
}
public void removeAll() {
checkWidget();
TableItem[] items = getItems();
for( int i = 0; i < items.length; i++ ) {
if( !items[ i ].isDisposed() ) {
items[ i ].dispose();
}
}
topIndex = 0;
}
public void clear( final int index ) {
checkWidget();
TableItem item = getItem( index );
item.clear();
}
/////////////////////////////
// Selection handling methods
public int getSelectionIndex() {
// TODO: [fappel] currently we do not have an focus indicator, so
// we return simply return the first index in range
int selectionIndex = -1;
TableItem[] currentSelection = getSelection();
if( currentSelection.length > 0 ) {
for( int i = 0; selectionIndex == -1 && i < itemHolder.size(); i++ ) {
if( itemHolder.getItem( i ) == currentSelection[ 0 ] ) {
selectionIndex = i;
}
}
}
return selectionIndex;
}
public void setSelection( final int index ) {
if( index >= 0 && index < itemHolder.size() ) {
TableItem item = ( TableItem )itemHolder.getItem( index );
selection = new TableItem[] { item };
} else {
selection = EMPTY_SELECTION;
}
}
public int getSelectionCount() {
return getSelection().length;
}
public void setSelection( final int start, final int end ) {
// TODO: [fappel] style bits for single/multi selection
if( end >= 0 && start <= end ) {
int actualStart = Math.max( 0, start );
int actualEnd = Math.min( end, itemHolder.size() - 1 );
selection = new TableItem[ actualEnd - actualStart + 1 ];
int count = 0;
for( int i = actualStart; i < actualEnd + 1; i++ ) {
selection[ count ] = ( TableItem )itemHolder.getItem( i );
count++;
}
}
}
public TableItem[] getSelection() {
List buffer = new ArrayList();
for( int i = 0; i < selection.length; i++ ) {
if( !selection[ i ].isDisposed() ) {
buffer.add( selection[ i ] );
}
}
selection = new TableItem[ buffer.size() ];
buffer.toArray( selection );
return (org.eclipse.swt.widgets.TableItem[] )selection.clone();
}
public void setSelection( final int[] indices ) {
if( indices == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
// TODO: [fappel] style bits for single/multi selection
Integer[] filteredIndices = filterIndices( indices );
TableItem[] newSelection = new TableItem[ filteredIndices.length ];
for( int i = 0; i < filteredIndices.length; i++ ) {
int index = filteredIndices[ i ].intValue();
newSelection[ i ] = ( TableItem )itemHolder.getItem( index );
}
selection = newSelection;
}
public void setSelection( final TableItem[] items ) {
if( items == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
int[] indices = new int[ items.length ];
for( int i = 0; i < items.length; i++ ) {
indices[ i ] = indexOf( items[ i ] );
}
setSelection( indices );
}
public int[] getSelectionIndices() {
TableItem[] currentSelection = getSelection();
int[] result = new int[ currentSelection.length ];
for( int i = 0; i < currentSelection.length; i++ ) {
result[ i ] = indexOf( currentSelection[ i ] );
}
return result;
}
public boolean isSelected( final int index ) {
boolean result = false;
if( index >= 0 && index < itemHolder.size() ) {
Item item = itemHolder.getItem( index );
TableItem[] currentSelection = getSelection();
for( int i = 0; !result && i < currentSelection.length; i++ ) {
result = currentSelection[ i ] == item;
}
}
return result;
}
public void deselectAll() {
checkWidget();
selection = EMPTY_SELECTION;
}
//////////////////////////////////
// TopIndex and showItem/Selection
public void setTopIndex( final int topIndex ) {
checkWidget();
if( topIndex >= 0 && topIndex < getItemCount() ) {
this.topIndex = topIndex;
}
}
public int getTopIndex() {
checkWidget();
return topIndex;
}
public void showItem( final TableItem item ) {
checkWidget();
if( item == null ) {
error( SWT.ERROR_NULL_ARGUMENT );
}
if( item.isDisposed() ) {
error( SWT.ERROR_INVALID_ARGUMENT );
}
int itemIndex = indexOf( item );
// Show item as top item
setTopIndex( itemIndex );
// try to show it 2 rows above the bottom/last item
// TODO [rh] replace this once getClientArea is working
int height = getBounds().height
- getHeaderHeight()
- ScrollBar.SCROLL_BAR_HEIGHT;
int visibleRows = height / getItemHeight();
int idealTopIndex = itemIndex - visibleRows + 2;
if( idealTopIndex >= getItemCount() ) {
idealTopIndex = getItemCount() - 1;
}
setTopIndex( idealTopIndex );
}
public void showSelection() {
checkWidget();
int index = getSelectionIndex();
if( index != -1 ) {
TableItem item = ( TableItem )itemHolder.getItem( index );
showItem( item );
}
}
////////////////////
// Visual appearance
public void setHeaderVisible( final boolean headerVisible ) {
checkWidget();
this.headerVisible = headerVisible;
}
public boolean getHeaderVisible() {
checkWidget();
return headerVisible;
}
public boolean getLinesVisible() {
checkWidget();
return linesVisible;
}
public void setLinesVisible( final boolean linesVisible ) {
checkWidget();
this.linesVisible = linesVisible;
}
///////////////////////////////////
// Dimensions and size calculations
public int getItemHeight () {
checkWidget();
int result = DEFAULT_ITEM_HEIGHT;
if( itemHolder.size() > 0 ) {
TableItem item = ( TableItem )itemHolder.getItem( 0 );
result = item.getHeight();
}
return result;
}
public int getHeaderHeight() {
checkWidget();
int result = 0;
if( headerVisible ) {
// TODO [rh] preliminary implementation
result = FontSizeEstimation.getCharHeight( getFont() ) + 4;
}
return result;
}
public int getGridLineWidth () {
checkWidget();
return GRID_WIDTH;
}
//////////////////
// Selection event
public void addSelectionListener( final SelectionListener listener ) {
SelectionEvent.addListener( this, listener );
}
public void removeSelectionListener( final SelectionListener listener ) {
SelectionEvent.removeListener( this, listener );
}
/////////////////////////////
// Create and destroy columns
final void createColumn( final TableColumn column, final int index ) {
columnHolder.insert( column, index );
}
final void destroyColumn( final TableColumn column ) {
columnHolder.remove( column );
}
////////////////////////////
// Create and destroy items
final void createItem( final TableItem item, final int index ) {
itemHolder.insert( item, index );
}
final void destroyItem( final TableItem item ) {
itemHolder.remove( item );
if( topIndex > getItemCount() - 1 ) {
topIndex = getItemCount() - 1;
}
}
//////////////////
// helping methods
private Integer[] filterIndices( final int[] indices ) {
Set buffer = new HashSet();
for( int i = 0; i < indices.length; i++ ) {
if( indices[ i ] >= 0 && indices[ i ] < itemHolder.size() ) {
buffer.add( new Integer( indices[ i ] ) );
}
}
Integer[] result = new Integer[ buffer.size() ];
buffer.toArray( result );
Arrays.sort( result );
return result;
}
private static int checkStyle( final int style ) {
int result = style;
result |= SWT.H_SCROLL | SWT.V_SCROLL;
return checkBits( result, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0 );
}
}