/******************************************************************************* * Copyright (c) 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * rmcamara@us.ibm.com - initial API and implementation * tom.schindl@bestsolution.at - various significant contributions *******************************************************************************/ package org.eclipse.nebula.jface.gridviewer; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Iterator; import java.util.List; import org.eclipse.jface.viewers.AbstractTableViewer; import org.eclipse.jface.viewers.CellLabelProvider; import org.eclipse.jface.viewers.ColumnViewerEditor; import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent; import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.jface.viewers.ViewerRow; import org.eclipse.nebula.jface.gridviewer.internal.CellSelection; import org.eclipse.nebula.jface.gridviewer.internal.SelectionWithFocusRow; import org.eclipse.nebula.widgets.grid.Grid; import org.eclipse.nebula.widgets.grid.GridItem; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Item; import org.eclipse.swt.widgets.Widget; /** * A concrete viewer based on an Grid control. * <p> * This class is not intended to be subclassed outside the viewer framework. It * is designed to be instantiated with a pre-existing Grid control and * configured with a domain-specific content provider, label provider, element * filter (optional), and element sorter (optional). * <p> * Content providers for grid table viewers must not implement the {@code * ITreeContentProvider} interface. Instead a {@link GridTreeViewer} should be * used. * <p> */ public class GridTableViewer extends AbstractTableViewer { /** This viewer's grid control. */ private Grid grid; private GridViewerRow cachedRow; private CellLabelProvider rowHeaderLabelProvider; /** * If true, this grid viewer will ensure that the grid's rows / GridItems * are always sized to their preferred height. */ private boolean autoPreferredHeight = false; /** * Creates a grid viewer on a newly-created grid control under the given * parent. The grid control is created using the SWT style bits * <code>MULTI, H_SCROLL, V_SCROLL,</code> and <code>BORDER</code>. The * viewer has no input, no content provider, a default label provider, no * sorter, and no filters. * * @param parent * the parent control */ public GridTableViewer(Composite parent) { this(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); } /** * Creates a grid viewer on a newly-created grid control under the given * parent. The grid control is created using the given SWT style bits. The * viewer has no input, no content provider, a default label provider, no * sorter, and no filters. * * @param parent * the parent control * @param style * the SWT style bits used to create the grid. */ public GridTableViewer(Composite parent, int style) { this(new Grid(parent, style)); } /** * Creates a grid viewer on the given grid control. The viewer has no input, * no content provider, a default label provider, no sorter, and no filters. * * @param grid * the grid control */ public GridTableViewer(Grid grid) { this.grid = grid; hookControl(grid); } /** * Returns the underlying Grid Control. * * @return grid control. */ public Grid getGrid() { return grid; } /** {@inheritDoc} */ protected ViewerRow internalCreateNewRowPart(int style, int rowIndex) { GridItem item; if (rowIndex >= 0) { item = new GridItem(grid, style, rowIndex); } else { item = new GridItem(grid, style); } return getViewerRowFromItem(item); } /** {@inheritDoc} */ protected ColumnViewerEditor createViewerEditor() { return new GridViewerEditor(this, new ColumnViewerEditorActivationStrategy(this), ColumnViewerEditor.DEFAULT); } /** {@inheritDoc} */ protected void doClear(int index) { // TODO Fix when grid supports virtual } /** {@inheritDoc} */ protected void doClearAll() { // TODO Fix when grid supports virtual } /** {@inheritDoc} */ protected void doSetItemCount(int count) { // TODO Once grid supports virtual } /** {@inheritDoc} */ protected void doDeselectAll() { grid.deselectAll(); } /** {@inheritDoc} */ protected Widget doGetColumn(int index) { return grid.getColumn(index); } /** {@inheritDoc} */ protected int doGetColumnCount() { return grid.getColumnCount(); } /** {@inheritDoc} */ protected Item doGetItem(int index) { return grid.getItem(index); } /** {@inheritDoc} */ protected int doGetItemCount() { return grid.getItemCount(); } /** {@inheritDoc} */ protected Item[] doGetItems() { return grid.getItems(); } /** {@inheritDoc} */ protected Item[] doGetSelection() { return grid.getSelection(); } /** {@inheritDoc} */ protected int[] doGetSelectionIndices() { return grid.getSelectionIndices(); } /** {@inheritDoc} */ protected int doIndexOf(Item item) { return grid.indexOf((GridItem) item); } /** {@inheritDoc} */ protected void doRemove(int[] indices) { grid.remove(indices); } /** {@inheritDoc} */ protected void doRemove(int start, int end) { grid.remove(start, end); } /** {@inheritDoc} */ protected void doRemoveAll() { grid.removeAll(); } /** {@inheritDoc} */ protected void doSetSelection(Item[] items) { GridItem[] items2 = new GridItem[items.length]; for (int i = 0; i < items.length; i++) { items2[i] = (GridItem) items[i]; } grid.setSelection(items2); grid.showSelection(); } /** {@inheritDoc} */ protected void doSetSelection(int[] indices) { grid.setSelection(indices); } /** {@inheritDoc} */ protected void doShowItem(Item item) { grid.showItem((GridItem) item); } /** {@inheritDoc} */ protected void doShowSelection() { grid.showSelection(); } /** {@inheritDoc} */ protected Item getItemAt(Point point) { return grid.getItem(point); } /** {@inheritDoc} */ public Control getControl() { return grid; } /** {@inheritDoc} */ protected ViewerRow getViewerRowFromItem(Widget item) { if (cachedRow == null) { cachedRow = new GridViewerRow((GridItem) item); } else { cachedRow.setItem((GridItem) item); } return cachedRow; } /** * {@inheritDoc} */ protected void doResetItem(Item item) { GridItem gridItem = (GridItem) item; int columnCount = Math.max(1, grid.getColumnCount()); for (int i = 0; i < columnCount; i++) { gridItem.setText(i, ""); //$NON-NLS-1$ gridItem.setImage(null); } } /** * {@inheritDoc} */ protected void doSelect(int[] indices) { grid.select(indices); } /** * When set to true, this grid viewer will ensure that each of the grid's * items is always automatically sized to its preferred height. The default * is false. * <p> * Since this mechanism usually leads to a grid with rows of different * heights and thus to a grid with decreased performance, it should only be * applied if that is intended. To set the height of all items to a specific * value, use {@link Grid#setItemHeight(int)} instead. * <p> * When a column with activated word wrapping is resized by dragging the * column resizer, the items are only auto-resized properly if you use * {@link GridViewerColumn} to create the columns. * <p> * When this method is called, existing rows are not resized to their * preferred height. Therefore it is suggested that this method be called * before rows are populated (i.e. before setInput). */ public void setAutoPreferredHeight(boolean autoPreferredHeight) { this.autoPreferredHeight = autoPreferredHeight; } /** * @return true if this grid viewer sizes its rows to their preferred height * @see #setAutoPreferredHeight(boolean) */ public boolean getAutoPreferredHeight() { return autoPreferredHeight; } /** {@inheritDoc} */ protected void doUpdateItem(Widget widget, Object element, boolean fullMap) { super.doUpdateItem(widget, element, fullMap); updateRowHeader(widget); if (autoPreferredHeight && !widget.isDisposed()) ((GridItem) widget).pack(); } private void updateRowHeader(Widget widget) { if (rowHeaderLabelProvider != null) { ViewerCell cell = getViewerRowFromItem(widget).getCell( Integer.MAX_VALUE); rowHeaderLabelProvider.update(cell); } } /** * Label provider used by calculate the row header text * * @param rowHeaderLabelProvider * the provider */ public void setRowHeaderLabelProvider( CellLabelProvider rowHeaderLabelProvider) { this.rowHeaderLabelProvider = rowHeaderLabelProvider; } /** * Refresh row headers only * * @param element * the element to start or <code>null</code> if all rows should * be refreshed */ public void refreshRowHeaders(Object element) { boolean refresh = element == null; GridItem[] items = getGrid().getItems(); for (int i = 0; i < items.length; i++) { if (refresh || element.equals(items[i].getData())) { refresh = true; updateRowHeader(items[i]); } } } /** * {@inheritDoc} */ public void editElement(Object element, int column) { try { getControl().setRedraw(false); Widget item = findItem(element); if (item != null) { ViewerRow row = getViewerRowFromItem(item); if (row != null) { ViewerCell cell = row.getCell(column); if (cell != null) { triggerEditorActivationEvent(new ColumnViewerEditorActivationEvent( cell)); } } } } finally { getControl().setRedraw(true); } // } } /** * {@inheritDoc} */ protected void setSelectionToWidget(ISelection selection, boolean reveal) { if( ! grid.isCellSelectionEnabled() || !(selection instanceof CellSelection) ) { super.setSelectionToWidget(selection, reveal); if( selection instanceof SelectionWithFocusRow ) { Object el = ((SelectionWithFocusRow)selection).getFocusElement(); if( el != null ) { GridItem[] items = grid.getItems(); for( int i = 0; i < items.length; i++) { GridItem item = items[i]; if( item.getData() == el || item.getData().equals(el) || (getComparer() != null && getComparer().equals(item.getData(), el)) ) { grid.setFocusItem(item); break; } } } } } else { CellSelection cellSelection = (CellSelection) selection; List l = cellSelection.toList(); GridItem[] items = grid.getItems(); ArrayList pts = new ArrayList(); for( int i = 0; i < items.length; i++ ) { Iterator it = l.iterator(); Object itemObject = items[i].getData(); while( it.hasNext() ) { Object checkObject = it.next(); if( itemObject == checkObject || (getComparer() != null && getComparer().equals(itemObject, checkObject) ) ) { Iterator idxIt = cellSelection.getIndices(checkObject).iterator(); while( idxIt.hasNext() ) { Integer idx = (Integer) idxIt.next(); pts.add(new Point(idx.intValue(),i)); } } } } Point[] tmp = new Point[pts.size()]; pts.toArray(tmp); grid.setCellSelection(tmp); if( cellSelection.getFocusElement() != null ) { Object el = cellSelection.getFocusElement(); for( int i = 0; i < items.length; i++) { GridItem item = items[i]; if( item.getData() == el || item.getData().equals(el) || (getComparer() != null && getComparer().equals(item.getData(), el)) ) { grid.setFocusItem(item); break; } } } } } /** * {@inheritDoc} */ public ISelection getSelection() { if (!grid.isCellSelectionEnabled()) { IStructuredSelection selection = (IStructuredSelection) super .getSelection(); Object el = null; if (grid.getFocusItem() != null) { el = grid.getFocusItem().getData(); } return new SelectionWithFocusRow(selection.toList(), el, getComparer()); } else { return createCellSelection(); } } private CellSelection createCellSelection() { Point[] ps = grid.getCellSelection(); Arrays.sort(ps, new Comparator() { public int compare(Object arg0, Object arg1) { Point a = (Point) arg0; Point b = (Point) arg1; int rv = a.y - b.y; if (rv == 0) { rv = a.x - b.x; } return rv; } }); ArrayList objectList = new ArrayList(); ArrayList indiceLists = new ArrayList(); ArrayList indiceList = new ArrayList(); int curLine = -1; for (int i = 0; i < ps.length; i++) { if (curLine != ps[i].y) { curLine = ps[i].y; indiceList = new ArrayList(); indiceLists.add(indiceList); objectList.add(grid.getItem(curLine).getData()); } indiceList.add(new Integer(ps[i].x)); } Object focusElement = null; if (grid.getFocusItem() != null) { focusElement = grid.getFocusItem().getData(); } return new CellSelection(objectList, indiceLists, focusElement, getComparer()); } }